Рассылка закрыта
При закрытии подписчики были переданы в рассылку "LinuxCenter News Channel: новости Linux" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Linux Gazette на русском
Информационный Канал Subscribe.Ru |
Linux Gazette на русском | Выпуск #96 | Тираж 7686 экз.
...будешь третьим!...
...хроники всех времён и народов...
Всем привет! Вот и подходит к концу трилогия о Ruby. Как и
в любом сериале, здесь всё заканчивается хорошо. :)
Спасибо за отличный перевод Андрею Киселёву! Присылайте свои вопросы и замечания по адресу lgrus@lrn.ru и, если не трудно,
сразу указывайте, можно ли использовать Ваши письма в
рассылке. Александр Куприн В первой части мы рассмотрели
основные синтаксические конструкции языка программирования Ruby. Вторая часть была посвящена
итераторам и основным принципам
объектно-ориентированного программирования. В этой
части мы поговорим об объектно-ориентированном программировании
более детально. Метод -- это некоторая функция, описывающая
реакцию объекта на поступивший запрос. Взгляните на пример вызова
метода, приведенный ниже: Из примера видно, что для строкового объекта
вызывается метод с именем length'. Немного усложним: Из этого примера видно, что решение о том какой метод вызвать
принимается во время исполнения и, что выбор этот зависит от
содержимого переменной. (в первом случае переменная foo
представляется как строковая переменная, во втором -- как массив
прим. перев.). У читателя может возникнуть вопрос: "Как же так? Ведь длина
строки и длина массива считаются по разному?". Не стоит
беспокоиться. К счастью, Ruby автоматически выбирает
соответствующий ситуации метод. Эта особенность в
объектно-ориентированном программировании называется
полиморфизмом. Нет никакой необходимости знать о том как работает тот или иной
метод, но каждый должен знать о том какие методы имеются у объекта.
При вызове неизвестного объекту метода, возникает ошибка. Например,
попробуйте вызвать метод "length"для объекта
"foo", присвоив ему предварительно значение
"5". Я уже упоминал о специальной псевдопеременной
self. Она определяет объект, чей метод
был вызван. Однако указание этой переменной очень часто опускается,
например: может быть сокращено до Эти два вызова идентичны друг другу, просто второй способ
является сокращенным вариантом первого. Реальный мир состоит из объектов, которые могут быть
классифицированы. Например, годовалый малыш, увидев собаку, думает
о ней как "гав-гав". В терминах объектно-ориентированного
программирования, "гав-гав" -- это
класс, а объект, принадлежащий классу --
экземпляр класса. В Ruby, как и в других объектно-ориентированных языках
программирования, сперва определяется класс, чтобы описать
поведение объекта, а затем создается экземпляр класса -- отдельный
объект. А теперь давайте определим класс. Описание класса должно начинаться с ключевого слова
class и заканчиваться ключевым словом
end. Ключевое слово def в данном
контексте начинает определение метода класса. Итак, мы описали класс с именем Dog', а теперь создадим
объект. Этот код создает новый экземпляр класса Dog и связывает его с
переменной tommy. Метод new' любого класса создает новый
экземпляр этого класса. Теперь переменная tommy обладает свойствами
класса Dog и может "прогавкать" (метод bark'). Вы когда нибудь задавались вопросом -- как разные люди
классифицируют объекты? Например, как люди видят собаку? Математик
может описать собаку как комбинацию чисел и геометрических фигур.
Физик -- как результат работы естественных и искусственных сил. Моя
сестра (биолог) может представить собаку как разновидность
отряда псовых домашних (canine domesticus). Для
нее собака -- это разновидность псовых, псовые -- разновидность
млекопитающих, а млекопитающие -- всегда животные. Отсюда видно, что классификация объектов имеет форму иерархии,
хотя и не всегда. Посмотрим, как это можно реализовать в Ruby. Из примера видно, что класс Cat не имеет определения метода
breath (рус. - "дыхание", прим. перев.),
но этот метод наследуется от родительского класса Animal. И имеет
дополнительный специфичный метод bark' (рус. -
"лаять", здесь следует читать как "звук, издаваемый
животным", прим. перев.). Известно, что свойства родительского класса не всегда
наследуются потомками. Например, пингвины не могут летать, хотя и
являются птицами. Однако пингвины несут в себе многие другие черты,
присущие птицам, например, они откладывают яйца. Подобные случаи
могут быть реализованы и в Ruby, однако оставляю читателям
возможность разобраться с этим самим. При создании нового класса, наследующего черты родительского
класса, нам необходимо будет только определить методы, описывающие
различия между потомком и родителем. Это одно из достоинств
объектно-ориентированного программирования, которое иногда называют
"дифференциальным программированием". Мы уже наблюдали различия в поведении экземпляров дочерних
классов после переопределения методов родительского класса.
Посмотрите на пример ниже: В дочернем классе, переопределяющем метод родительского класса,
можно вызвать оригинальный метод родителя с помощью ключевого слова
super'. Попробуйте запустить этот код: Надеюсь, этих простых примеров достаточно для того, чтобы понять
принципы наследования и переопределения методов. Возможность вызова метода может быть ограничена. Для функции
(определяемой на верхнем уровне) смотрите ниже: Теперь, когда любой класс может вызвать метод sqr', давайте
попробуем вызвать его с помощью псевдопеременной self': Как показано выше, вызов функции с помощью self' приводит к
выдаче сообщения об ошибке. Это сообщение недостаточно понятно
(интуитивно), что оно означает? Суть в том, что функции, определенные за пределами какого либо
класса должны вызываться как простые функции, а не как методы.
Посмотрите какое сообщение об ошибке получается при вызове не
определенного метода. Методы, определенные как простые функции, должны вызываться как
простые функции, подобно функциям C++, даже в пределах класса. Область видимости метода может быть ограничена ключевыми словами
"public" и "private", где public -- определяет
общедоступные методы класса, а private -- скрытые, которые могут
быть вызваны только из других методов класса. Из этого примера все должно быть понятно. Поведение экземпляра определяется его принадлежностью к тому или
иному классу, однако порой возникает необходимость в наделении
объекта некоторой, свойственной только ему, индивидуальностью. В
большинстве языков программирования вам придется создавать для
этого отдельный класс. Ruby же позволяет добавить специфичный метод
к конкретному экземпляру (объекту) без лишних телодвижений. Где t1 и t2 -- принадлежат одному и тому же классу и тем не
менее, для экземпляра t2 переопределяется метод size',
обеспечивая его индивидуальность. Такой специфичный метод
называется единичный метод (singleton
method). В качестве примера применения единичного метода можно привести
кнопки в окне программы с графическим интерфейсом, где каждая
кнопка должна выполнять свои действия по нажатии. Мы можем
переопределить метод, обрабатывающий нажатие у каждой из имеющихся
кнопок. Модули в Ruby очень похожи на классы, но используются для
группировки родственных классов в одном месте. Вот три основных
отличия модулей от классов: Грубо говоря, существуют две основные причины использования
модулей. Первая -- собрать методы и константы в одном месте.
Например: Оператор ::' указывает на то, что константа определена в
соответствующем модуле или классе. Чтобы обращаться к методам или
константам напрямую, следует использовать директиву
include' Другая причина -- "смешение" (mixin') модулей.
Смысл этого термина достаточно сложен для понимания, поэтому
остановимся на нем подробнее. Некоторые объектно-ориентированные языки допускают наследование
от нескольких родительских классов, такая возможность называется
множественным наследованием. Ruby преднамеренно лишен этой
возможности. Вместо этого он допускает смешение (mixin) с
модулем. Как сказано выше, модуль во многом похож на класс. Методы или
константы в модуле не могут наследоваться, но могут быть добавлены
в другие модули или классы с помощью директивы include. Таким
образом, подключение модуля к определению, добавляет (подмешивает)
свойства модуля к свойствам класса или модуля. Смешение модулей можно наблюдать в стандартной библиотеке, где в
результате "смешения" модулей с классом, имеющим метод
each', возвращающий каждый элемент, последний получает в свое
распоряжение методы sort', find' и т.п.. Между множественным наследованием и "смешением"
существуют следующие отличия: Эти различия запрещают сложные взаимоотношения между классами,
простота ставится во главу угла. По этой причине Ruby не
поддерживает множественного наследования. В языках, поддерживающих
множественное наследование, вполне может возникнуть ситуация, когда
классы имеют несколько предков, а взаимоотношения между
экземплярами классов создают запутанную сеть... Ситуация слишком
сложна для восприятия человеческим мозгом, по крайней мере --
моим... С другой стороны, смешение представляет все это, просто как
"коллекцию специфических свойств из всего, что было
добавлено". Даже в языках с множественным наследованием, считается, что
лучше расширять классы с использованием смешения, нежели
разрабатывать сложные отношения наследования. В Ruby эта идея была
продвинута дальше, заменив собой идею множественного
наследования. Представьте себе, что вы пишите программу, которая обрабатывает
некоторые сигналы. Знакомые с этим поймут всю прелесть передачи
процедуры в виде аргумента методу (который занимается обработкой
сигналов). Процедурные объекты создаются с помощью встроенного метода
proc. Исполняемый код записывается внутри
фигурных скобок. Вызов на исполнение производится методом
call процедурного объекта. Смотрите
ниже: C-программисты обнаружат сходство между процедурными объектами и
указателями на функции. Успехов в труде...
Я -- студент последнего курса Правительственного
Колледжа Компьютерных Наук в городе Трикур (Trichur), Индия. Кроме
Linux, я с большим удовольствием занимаюсь изучением физики.
Команда переводчиков: Со всеми предложениями, идеями и комментариями обращайтесь к
Александру Куприну (lgrus@lrn.ru). Убедительная
просьба: указывайте сразу, не возражаете ли Вы против публикации
Ваших отзывов в рассылке. Сайт рассылки: http://gazette.linux.ru.net
Программирование на языке Ruby, часть
3
Автор: Hiran
Ramankutty
Перевод: Андрей Киселев
Методы
print "asdfgh".length
^D
6
foo = "abc"
print foo.length,"\n"
foo = [1, 2]
print foo.length,"\n"
^D
3
2
self.method_name(arguments...)
method_name(arguments...)
Классы
class Dog
def bark
print "Гав гав\n"
end
end
^D
tommy = Dog.new
tommy.bark
^D
Гав гав
Наследование
class Animal
def breath
print "Вдох и выдох\n"
end
end
class Cat<Animal
def bark
print "мяу\n"
end
end
tama = Cat.new
tama.breath
tama.bark
^D
Вдох и выдох
мяу
Переопределение методов
class Human
def print_id
print "Я - человек.\n"
end
def train_toll(age)
print "Детский билет.\n" if age < 12
end
end
Human.new.print_id
class Student1<Human
def print_id
print "Я - студент.\n"
end
end
Student1.new.print_id
class Student2<Human
def print_id
super
print "И студент.\n"
end
end
Student2.new.print_id
^D
Я - человек.
Я - студент.
Я - человек.
И студент.
class Student3<Human
def train_toll(age)
super(11) # принудительно снижаем возраст
end
end
Student3.new.train_toll(25)
^D
Детский билет.
Еще о методах
def sqr(x)
x * x
end
print sqr(5)
^D
25
Если определение функции находится за пределами описания класса, то
она добавляется как метод класса Object. Класс Object является
базовым для всех остальных классов -- в Ruby все классы являются
потомками класса Object. Таким образом, метод sqr' может
вызываться из других классов.
print self.sqr(5)
^D
ERR: private method sqr' called for (Object)
class Test
def bar
print "bar -< "
foo
end
private
def foo
print "foo\n"
end
end
temp = Test.new
temp.bar
temp.foo
^D
bar -< foo
ERR: private method foo' called for (Test)
Единичные (Singleton) методы
class SingletonTest
def size
print "25\n"
end
end
t1=SingletonTest.new
t2=SingletonTest.new
def t2.size
print "10\n"
end
t1.size
t2.size
^D
25
10
Модули
print Math::PI,"\n"
print Math.sqrt(2),"\n"
^D
3.141592654
1.414213562
include Math
print sqrt(2),"\n"
print PI,"\n"
^D
1.414213562
3.141592654
Процедурные объекты
obj = proc{print "Hello world\n"}
obj.call
^D
Hello world
Заключение
Эта часть является заключительной в серии. Цель серии была -- дать
начальные сведения о программировании на языке Ruby. Я сейчас
слишком занят своим дипломным проектом, чтобы выделить время на
более глубокое изучение Ruby. Но в будущем, как только позволит
время, я это продолжу.
Hiran Ramankutty
Published in Issue 86 of Linux Gazette, January
2003
Владимир Меренков, Александр Михайлов, Иван Песин, Сергей
Скороходов, Александр Саввин, Роман Шумихин, Александр Куприн,
Андрей Киселев
Эту статью можно взять здесь: http://gazette.linux.ru.net/lg86/ramankutty.html
http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу
В избранное | ||