2. Модификация и создание пользовательских классов
2. Модификация и создание пользовательских классов
Ruby является объектно-ориентированным языком программирования. Давайте рассмотрим особенности представления классов.
Объекты и классы
В реальной жизни все объекты обладают индивидуальными свойствами. Но, введя некоторые обобщения, можно поделить объекты реальной жизни на группы. Каждая из таких групп будет обладать одинаковым набором свойств и, как следствие, к ней будут применимы одинаковые наборы действий.
classString
def reverse
"?????"
end
def msiu
"МГИУ"
end
end
a="12345"
putsa.reverse
putsa.msiu
В языке программирования Ruby для описания набора свойств групп объектов и применимых к этим объектам действий используется такое понятие, как классы.
Класс – это формальное описание основных свойств объекта (его атрибутов) и методов, применимых к нему Задав описание класса, в дальнейшем можно создавать столько его экземпляров, сколько потребуется.
Классы в Ruby – открыты; если нам не хватает функциональности класса, то мы можем дополнить класс новым методом или переопределить старый.
Иерархия классов и полиморфизм
Зачастую из класса можно выделить группу объектов, обладающую каким-либо специальным свойством. Такую группу называют подклассом, или дочерним классом. Дочерний класс наследует все свойства родительского класса, но обладает отдельной функциональностью. С помощью символа < указывается родительский класс.
Пример 1.
Птицы всех видов несут яйца, но не все птицы умеют летать. Хотя в классе Penguin и не описан метод lay_egg, при необходимости он ищется (и находится!) в родительском классе (принцип наследования, иерархическая организация классов). Метод fly переопределен для пингвинов, и реакция на вызов этого метода определяется принадлежностью к тому или
Модификация и создание пользовательских классов иному классу (полиморфизм, различные реалиции на одинаковую команду).
class Bird def lay_egg
puts "Я из класса #{self.class}. Яйцо снесено!" end
def fly
puts "Все представители класса #{self.class} умеют летать!"
end
end
class Penguin < Bird def fly
puts "Представители класса #{self.class} не летают…" end end
b = Bird.new; b.lay_egg; b.fly p = Penguin.new; p.lay_egg; p.fly
Создание класса
Дальнейшее описание проиллюстрируем обыкновенными дробями. В процессе вычислений нередко возникает необходимость работы с дробными числами. Учитывая ограничения по точности представления чисел с плавающей точкой в компьютере, иногда бывает необходимо производить вычисления в терминах обыкновенных дробей, представляющих собой отношение целого числителя и целого знаменателя. В Ruby имеется класс Rational, описывающий такие дроби. Представим на время, что его нет и создадим нечто подобное.
classFrac
definitialize(a,b)
raise’Divisionbyzero’ifb.to_i == 0
@numerator,@denominator = a.to_i, b.to_i
end
end
fr=Frac.new(1,2)
Метод initialize называется конструктором класса. Он вызывается каждый раз, когда мы создаем экземпляр класса при помощи метода new.
Конструкция raise вызывает исключительную ситуацию (об этом будет рассказано позже) и выдает соответствующее сообщение об ошибке.
Переменные экземпляра
Переменные enumerator, @denominator – это переменные атрибуты экземпляра класса. В именах переменных экземпляра необходимо использовать префикс @. Каждый объект, принадлежащий данному классу, имеет свои собственные значения этих атрибутов (свойства), но пока их можно использовать только внутри методов самого класса. При попытке обратиться к таким переменным извне класса будет выдано сообщение об ошибке. Что же делать, если хочется иметь доступ к переменным экземпляра вне класса?
Один способ состоит в создании методов, возвращающих значение соответствующего атрибута. Но в случае большого числа атрибутов такой подход не удобен. Язык Ruby предлагает более удобную возможность.
Для контроля доступа к переменным экземпляра можно использовать макросы attr_reader (для чтения), attr_writer (для изменения значения) и attr_accessor (для выдачи разрешения на оба действия).
Метод to_s, присутствующий в классе, определяет, как объект должен отображаться при печати.
Переопределение операторов
Оперирование дробями предполагает возможность производить математические действия, например, сложение. Символ + является оператором языка Ruby. Но некоторые операторы для удобства пользователя могут быть переопределены. Но не все! Например, + может быть переопределен, = нет.
Реализуем операцию сложения дробей самостоятельно. Чтобы дроби не получались избыточными, нам надо будет уметь их сокращать. Это позволяет сделать алгоритм Евклида.
Модификация и создание пользовательских классов
class Frac
def initialize(a, b)
raise ’Division by zero’ if b.to_i == 0
@numerator,@denominator = a.to_i, b.to_i
simplify()
end
end
fr=Frac.new(1,2)
def +(b)
if b.class != Frac
raise "Undefined method + for class Frac and #{b.class}!"
end
return Frac.new(self.numerator * b.denominator + b.numerator * self.denominator,
self.denominator * b.denominator)
end
private
def simplify()
x, y = @numerator.abs, @denominator.abs x, y = y, x % y while x * y > 0
m = x + y
@numerator, @denominator = @numerator / m, @denominator / m
end
end
В операторе сложения мы проверяем, что второй аргумент операции + тоже является объектом типа Frac.
Для каждого объекта в Ruby можно применить метод class, чтобы выяснить, к какому классу он относится. Более правильно проверять, что объект относится к тому или иному классу, при помощи метода kind_of?.
Ключевое слово self указывает на объект, вызвавший метод. Запись self.numerator эквивалентна enumerator.
Метод simplify реализует алгоритм Евклида, упрощающий дроби. Чтобы у нас всегда были упрощенные дроби, он вызывается в конструкторе класса. Ключевое слово private определяет право доступа к следующим за ним методам только внутри класса. Таким образом, метод simplify не может быть использован вне класса Frac.
Аналогично + мы можем также переопределять и логические операторы. Например, оператор ==, позволяющий сравнивать два объекта на равество.
class Frac def ==(b)
if !b.kind_of?(Frac)
raise "Undefined method == for class Frac and #{b.class}!" end
return (self.numerator == b.numerator and self.denominator == b.denominator)
end
end
Если нам хочется, чтобы объекты нашего класса можно было бы сравнивать между собой (и, как следствие, сортирововать массив таких объектов методом sort), то необходимо переопределить метод <=>. Метод <=> должен возвращать 0 если объекты равны между собой; отрицательное число, если первый аргумент меньше второго; и положительное число в остальных случаях.
class Frac def <=>(b)
if !b.kind_of?(Frac)
raise "Undefined method <=> for class Frac and #{b.class}!" end
return self.numerator * b.denominator -
b. numerator * self.denominator <=> 0
end
end
Переменные класса
В случае необходимости иметь какую-то одинаковую для всех объектов класса характеристику используют переменные класса, которые синтаксически выделяются указанием префикса @@ в их имени.
Предположим, что нам потребовалось знать общее количество дробей, созданных при работе с классом Frac. Добавив в конструктор класса команду инкремента такой переменной, мы сможем узнать количество созданных дробей.
Методы класса
С понятием применения метода связано понятие ответственности за его выполнение. Иногда за то или иное действие отвечает не объект, а сам класс. В этом случае применяется метод класса. При его задании перед именем метода указывается имя класса.
Пример 2. Рассмотрим класс R@Point, описывающий точки на плоскости. Пусть нам требуется найти расстояние между двумя точками. В первом случае мы перекладываем ответственность за выполнение метода на одну из точек. Требование выглядит так: «точка, вычисли расстояние до другой точки». В этом случае непонятно, почему одна из точек берет на себя ответственность за выполнение этой обязанности, ведь они обе участвуют в данной операции на равных правах. Второй подход состоит в команде, отдаваемой самому классу: «класс, определи расстояние между двумя объектами».
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
7.2.6. Создание пользовательских цепочек в таблице filter
7.2.6. Создание пользовательских цепочек в таблице filter Итак, у вас перед глазами наверняка уже стоит картинка движения пакетов через различные цепочки, и как эти цепочки взаимодействуют между собой! Вы уже должны ясно представлять себе цели и назначение данного сценария.
Глава 5. Создание пользовательских виджетов
Глава 5. Создание пользовательских виджетов В данной главе объясняются способы создания пользовательских виджетов с помощью средств разработки Qt. Пользовательские виджеты могут создаваться путем определения подкласса существующего виджета Qt или путем определения
Быстрый поиск переходов и создание пользовательских корзин
Быстрый поиск переходов и создание пользовательских корзин Поиск нужного видеоперехода на вкладке Effects (Эффекты) занимает некоторое время. Необходимо отыскать папку группы перехода, открыть ее, найти нужный переход. Быстро найти нужный переход можно по его названию.1. В
Создание пользовательских стилей
Создание пользовательских стилей Несмотря на то что в каждой версии Word количество заготовленных стилей увеличивается, весьма вероятно, что вы не найдете среди них именно то, что нужно вам в данный момент. По этой причине в Microsoft Word предусмотрена также возможность
Создание пользовательских шаблонов
Создание пользовательских шаблонов Благодаря шаблонам можно сэкономить много времени. Например, если вы постоянно работаете с какой-нибудь организацией и каждый раз вводите стандартное приветствие, реквизиты и т. д., удобно будет создать собственный шаблон на основе
Создание пользовательских исключений, раз…
Создание пользовательских исключений, раз… Всегда есть возможность генерировать экземпляр System.Exceptiоn, чтобы сигнализировать об ошибке времени выполнения (как показано в нашем первом примере), но часто бывает выгоднее построить строго типизированное исключение, которое
Создание пользовательских исключений, два…
Создание пользовательских исключений, два… Тип CarIsDeadException переопределяет свойство System.Exception.Message, чтобы установить пользовательское сообщение об ошибке. Однако задачу можно упростить, установив родительское свойство Message через входной параметр конструктора. В
Создание пользовательских исключений, три!
Создание пользовательских исключений, три! Если вы хотите построить "педантично точный" пользовательский класс исключения, то созданный вами тип должен соответствовать лучшим образцам, использующим исключения .NET. В частности, ваше пользовательское исключение должно
Создание пользовательских индексаторов
Создание пользовательских индексаторов Как программисты, мы прекрасно знаем, что с помощью индексов можно получить доступ к отдельным элементам, содержащимся в стандартном массиве.// Объявление массива целых значений.int[] myInts = {10, 9, 100, 432, 9874};// Использование операции [] для
Создание пользовательских подпрограмм преобразования
Создание пользовательских подпрограмм преобразования В C# есть два ключевых слова, explicit и implicit, предназначенные для управления тем, как типы должны отвечать на попытки преобразования. Предположим, что у нас есть следующие определения структур.public struct Rectangle { // Открыты для
Создание пользовательских обобщенных коллекций
Создание пользовательских обобщенных коллекций Итак, пространство имен System.Collections.Generic предлагает множество типов, позволяющих создавать эффективные контейнеры, удовлетворяющие требованиям типовой безопасности. С учетом множества доступных вариантов очень велика
Создание пользовательских атрибутов
Создание пользовательских атрибутов Первым шагом процесса построения пользовательского атрибута является создание нового класса, производного от System.Attribute. В продолжение автомобильной темы, используемой в этой книге, мы создадим новую библиотеку классов C# с именем
Создание пользовательских элементов управления Windows Forms
Создание пользовательских элементов управления Windows Forms Платформа .NET предлагает для разработчиков очень простой способ создания пользовательских элементов интерфейса. В отличие от (теперь уже считающихся устаревшими) элементов управления ActiveX, для элементов
Создание пользовательских диалоговых окон
Создание пользовательских диалоговых окон Теперь, когда вы понимаете роль базовых элементов управления Windows Forms и суть процесса построения пользовательских элементов управления, давайте рассмотрим вопрос создания пользовательских диалоговых окон. Здесь хорошей
Глава 2. Создание динамических и интерактивных пользовательских интерфейсов
Глава 2. Создание динамических и интерактивных пользовательских интерфейсов 2.0. Введение Когда iPhone только появился на рынке, он поистине задал стандарт интерактивности в мобильных приложениях. Приложения iOS были и остаются поразительно интерактивными — вы можете на
Константы пользовательских классов
Константы пользовательских классов Символические константы полезны не только при работе с предопределенными типами, такими как INTEGER. Они нужны и тогда, когда их значениями являются объекты классов, созданных разработчиком. В этом случае решение не столь