Андрей Васильев
2020
Мы управляем магазином подержанных книг. Каждую неделю проводится инвентаризация. Работники сканируют бар-коды на книгах и сохраняют их в CSV-списки.
"Date","ISBN","Price"
"2019-04-12","978-1-9343561-0-4",939.45
"2019-04-13","978-1-9343561-6-6",645.67
"2019-04-14","978-1-9343560-7-4",836.95
При проектировании решения в объектно-ориентированном подходе сначала необходимо идентифицировать ключевые сущности
Для нашего случая выделим следующие сущности:
BookInStock
Books
Для описания классов используется конструкция
Для создания объектов класса в Ruby используется метод new
::new
есть у каждого классаВ примере выше мы создали 2 объекта класса ClassName
и записали их в переменные object_one
и object_two
Методу можно передать данные, которые будут использованы при инициализации объекта:
После создания каждого объекта Ruby инициализирует объект, вызывая метод initiailize
и передавая ему параметры из конструктора
class BookInStock
def initialize(isbn, price)
@isbn = isbn
@price = Float(price) # Может выбросить исключение
end
end
@
p
и pp
показывают внутреннее состояние объектаputs
пытается преобразовать объект к строкеПри преобразовании объекта к строке вызывается метод to_s
, который можно переопределить для своего класса
to_s
не принимает аргументовto_s
должен вернуть строкуДля работы методов p
и pp
иногда разумно реализовать метод inspect
, который формирует представление об объекте с точки зрения программиста
В языке Ruby есть методы-помощники, упрощающие задачу описания атрибута на основе переменной экземпляра
Метод attr_reader
создаёт методы для получения значений переменных экземпляра
attr_reader
— метод для чтения значения переменной, при этом переменная не становится публичнойМетоду можно передать несколько имён переменных, но это усложняет совместную работу при использовании систем контроля версий
При написании классов согласно методологии объектно-ориентированного программирования мы должны придерживаться принципа инкапсуляции, при котором данными объекта должен управлять только этот объект
Чтение атрибута — это получение ссылки на «внутренний» объект
Если данный объект можно изменить, тогда нельзя сказать, что класс с данным атрибутом полностью управляет своими данными
Обычным для объектно-ориентированных языков способом изменения атрибута является создание специального метода
=
Метод attr_accessor
создаёт методы для чтения и записи данных в переменные экземпляра
Метод attr_writer
создаёт метод для записи данных. Зачастую не используется, так как сложно представить ситуацию, когда надо записывать данные, но не считывать их.
В Ruby вы всегда взаимодействуете с методами, а не с переменными экземпляра. Это позволяет зафиксировать интерфейс объекта и легко менять его реализацию в будущем
Можно описать атрибут, который выполняет более сложные действия по сравнению с чтением и записью
def price_in_copeks
Integer(@price * 100 + 0.5)
end
def price_in_copeks=(copeks)
@price = copeks / 100.0
end
book.price_in_copeks
book.price_in_copeks = 15
Во время решения реальных задач с помощью классов мы описываем не только реальные объекты, но также и технические элементы, необходимые для достижения цели
В нашем приложении необходимо обрабатывать информацию о множестве книг, которая записана в CSV-файлы
Определим интерфейс класса, который мы хотим реализовать
read_in_csv_data
total_value_in_stock
number_of_each_isbn
Класс Books
должен считывать данные из нескольких CSV-файлов, которые собираются разными устройствами
csv
CSV
, позволяющий читать и записывать CSV-документыforeach
"Date","ISBN","Price"
"2013-04-12","978-1-9343561-0-4",39.45
Класс Books
должен сохранять информацию о всех считанных книгах. Для её хранения будем использовать массив.
[]
<<
добавляет объект в конец массиваpush
добавляет один или несколько объектов в конец массиваRuby позволяет разработчикам определить альтернативные имена для публичных методов. Для создания псевдонима следует использовать метод alias_method
.
В Ruby 2.5 ввели альтернативное название для метода push
— append
Обычно один исходный файл на языке Ruby содержит один класс или один модуль, что
Желательно отделять модули, ответственные за взаимодействие с внешним миром (пользователи, файлы) от модулей, которые реализуют обработку данных
Для подключения других файлов используются методы
require
для подключения внешних библиотекrequire_relative
для подключения собственных файлов по относительному путиОтносительный путь строится относительно текущего файла
Ruby предоставляет 3 уровня контроля доступа к методам
public
) методы могут быть вызваны любым объектом
initialize
являются публичнымиprotected
) методы могут быть вызваны из любого объекта данного классаprivate
) методы могут быть вызваны только лишь внутри данного классаОтличия от знакомых вам языков программирования
Для указания контроля доступа используются методы public
, protected
, private
person2
содержит копию данныхperson2
объект person1
не изменяетсяПри применении данной техники вместо изменения текущего объекта создаётся копия оригинального объекта
class Maslo
attr_reader :weight # Только лишь чтение
def initialize(weight)
@weight = weight
end
def take(weight)
new Maslo(@weight - weight) # Новый объект
end
end