Готовый перевод Programming Ruby 1.9 (3rd edition): The Pragmatic Programmers' Guide / Программирование на Ruby 1.9 (3-е издание): Руководство прагматичного программиста: Classes, Objects, and Variables
<b>Глава 3</b>
Классы, Объекты и Переменные
Из примеров которые мы уже показали вы можете быть удивлены нашим предыдущим утверждением что Ruby является объектно-ориентированным языком. И так эта глава в которой мы это подтверждаем. Мы собираемся научить вас как создавать классы и объекты в Ruby и некоторые другие пути в которых Ruby мощнее чем большинство объектно ориентированных языков.
Как мы видели на странице 35 все чем мы манипулируем Ruby это объект. И каждый объект в Ruby был создан прямо или косвенно от класса. В этой главе мы более глубоко рассмотрим создание и манипулирование этими классами.
Ну давайте дадим самим себе простую проблему для решения. Давайте представим себе что мы руководим секонд-хенд книжным магазином. Каждую неделю мы проверяем продажи. Банда клерков использует портативные сканеры бар-кодов и проверяют каждую книгу на наших полках. Каждый сканер создает простой comma-separated value (CSV) файл содержащий одну строку для каждой сканированной книги. Строка содержит (исключая другие вещи) ISBN книги и ее цену. Кусок одного из эти файлов выглядит где то так:
<code>"Date","ISBN","Amount"</code>
<code>"2008-04-12","978-1-9343561-0-4",39.45 </code>
<code>"2008-04-13","978-1-9343561-6-6",45.67 </code>
<code>"2008-04-14","978-1-9343560-7-4",36.95 </code>
Наша работа это брать все CSV файлы и работать над тем сколько раз повторяется каждое название, так же как общая цена книг в стоке.
Когда вы разрабатываете объектно-ориентированную систему первый хороший шаг это понять, с чем вы имеете дело? Обычно каждый вид вещей становится классом в вашей финальной программе, а конкретные вещи экземплярами этих классов.
Ясно, что нам необходим класс для чтения и просмотра сканированной информации. Каждый экземпляр этого класса представляет собой отдельную строку информации, а все объекты, взятые вместе представят всю информацию полученную нами.
Давайте назовем этот класс <i>BooklnStock</i>.(Запомните имена классов начинаются с буквы верхнего регистра а имена методов обычно начинаются с буквы нижнего регистра.)
<code>class BooklnStock end</code>
Как мы видели в предыдущей главе мы можем создавать новые экземпляры этого класса с помощью new:
<code>a_book = BooklnStock.new another_book = BooklnStock.new</code>
После выполнения этого кода у нас было бы два различных объекта, оба класса BookInStock. Но, кроме того факта, что они не идентичны, эти два объекта одно и тоже - нет ничего, чем бы один отличался от другого. И, что еще хуже, эти объекты на самом деле не содержат никакой информации, для хранения которой они нам и нужны.
Лучший способ исправить это - снабдить объекты методом инициализации. Это позволит нам устанавливать состояние каждого объекта в момент создания. (Помните переменные экземпляра? Это те, которые начинаются с символа @.) Благодаря тому, что каждый объект в Ruby имеет свой собственный набор переменных экземпляра, каждый объект может находиться в своем собственном уникальном состоянии.
И так здесь наше обновленное определение класса:
<p style="font-family: times, serif; font-size:10pt; font-style:italic">Download samples/tutclasses_4.rb</p>
<code>class BooklnStock </code>
<code>def initialize(isbn, price) ©isbn = isbn ©price = Float(price) end end</code>
<i>initialize</i> это специальный метод в программах Ruby. Когда вы вызываете BooklnStock.new для создания нового объекта, Ruby выделяет какое то количество памяти для содержания не инициализированного объекта и вызывает метод <i>initialize</i> передавая любые параметры которые мы передали <i>new</i>. Это дает вам возможность написать код который определяет состояние объекта.
Для класса BooklnStock метод initialize берет два параметра. Эти два параметра работают также как локальные переменные с методом и так они выполняют локальную переменную именуемую конвенцией и начинающеюся с маленькой буквы. Но локальные переменные просто исчезают после инициализации метод возвращает значение, поэтому мы должны передавать их в переменных экземпляра. Это обычное поведение при инициализации метода, наша цель это настроить этот объект чтобы его можно было использовать во время возврата при инициализации.
Этот метод также иллюстрирует то, что часто сбивает с толку новичков в Ruby. Заметьте, как мы произносим "@isbn = isbn". Легко представить, что здесь две переменные, @isbn и isbn, которые как-то связаны - это выглядит так, будто-бы у них одно и то же имя. Но это не так. Первая - это переменная экземпляра, и символ "@" - это часть ее имени.
В завершение, этот код иллюстрирует простую проверку. Метод Float принимает аргумент и преобразует его в число с плавающей запятой. Программа завершается ошибкой, если преобразование прошло неудачно. (Позже в этой книге мы увидим, как обрабатывать исключительные ситуации.) То, что мы делаем здесь есть утверждение того, что можно принять любой объект в качестве параметра price, если этот параметр может быть преобразован в число с плавающей запятой. Мы можем передать методу число с плавающей запятой(float), целое число(integer) и даже строку(string), содержащую представление числа с плавающей запятой, и это будет работать. Теперь давайте попробуем. Создадим три объекта, каждый с уникальным начальным состоянием. Метод p выводит внутренне представление объекта. Используя его, можем видеть, что в каждом случае наши параметры были переданы объекту, а внутри объекта присвоены переменным экземпляра.
<code>Download samples/tutclasses_5.rb</code>
<code>class BooklnStock</code>
<code>def initialize(isbn, price) ©isbn = isbn ©price = Float(price) end end </code>
<code>b1 = BookInStock.new("isbn1", 3) </code>
<code>p b1</code>
<code>b2 = BookInStock.new("isbn2", 3.14)</code>
<code> p b2</code>
b3 = BookInStock.new("isbn3", "5.67")
p b3
Выводит:
# # #
Почему мы использовали для вывода объекта p, а не puts? Хорошо, дайте попробуем сделать тоже самое с помощью puts.
Download samples/tutclasses_6.rb
b1 = BookInStock.new("isbn1", 3)
puts bl
b2 = BookInStock.new("isbn2", 3.14)
puts b2
b3 = BookInStock.new("isbn3", 5.67)
puts b3
Выводит:
# # #
1. Да, мы в курсе, что не следует хранить цены в числах с плавающей точкой. У Ruby есть специальные классы, которые умеют хранить точные значения в числах с фиксированной точкой, но в этом разделе мы изучаем классы, а не арифметику.
Помните, что puts просто пишет строки из вашей программы в стандартный поток ввода-вывода. Когда вы передаете ему объект экземпляр класса неписаного Вами, в действительности он не знает, что с ним сделать. Поэтому puts использует очень простой подход: он пишет имя класса объекта, за которым следует двоеточие и уникальный идентификатора объекта (шестнадцатеричное число). Все это помешается внутри #<...>
Наш опыт подсказываем нам, что во время разработки мы печатаем объект BookInStock много раз, но форматирование по умолчанию оставляет желать лучшего. К счастью, в Ruby предусмотрен стандартный метод to_s, который преобразует объект в строку. Таким образом, когда мы пытаемся вывести наш BookInStock объект на экран, puts, чтобы получить строковое представление, вызывает у этого объекта метод to_s. Поэтому, чтобы выводить объект в более читабельном виде, давайте переопределим метод to_s:
Здесь происходит кое-что тривиальное и одновременно важное. Посмотрите как значения, которые мы присваиваем переменным экземпляра @isbn и @price в методе initialize, впоследствии доступны в методе to_s . Это демонстрирует, как работают переменные экземпляра - они сохраняются в каждом объекте и доступны всем методам экземпляра.
Объекты и атрибуты
Объекты BookInStock, которые мы до сих пор создавали, имеют внутреннее состояние (ISBN и цена). Это состояние для каждого объекта свое - другие объекты не имеют доступа к переменным экземпляра данного объекта. Вообще, это хорошо. Это означает, что объект сам ответственен за поддержание собственной целостности.
Однако, объект, который вообще не имеет открытых методов, довольно бесполезен - вы можете создать его, но вы ничего не можете с ним делать. Обычно вы будете определять методы, которые позволят управлять состоянием объекта, разрешая внешнему миру взаимодействовать с объектом. Эти видимые внешне аспекты объекта называются атрибуты.
Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод
Переведено на Нотабеноиде
http://notabenoid.org/book/10995/40834
Переводчики: Droidos, shaliko, tartuff22, kronos
Настройки
Готово:
