Читаем Программирование на языке Ruby полностью

Дальнейшее описание проиллюстрируем обыкновенными дробями. В процессе вычислений нередко возникает необходимость работы с дробными числами. Учитывая ограничения по точности представления чисел с плавающей точкой в компьютере, иногда бывает необходимо производить вычисления в терминах обыкновенных дробей, представляющих собой отношение целого числителя и целого знаменателя. В 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


Перейти на страницу:

Похожие книги

Фундаментальные алгоритмы и структуры данных в Delphi
Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет СЃРѕР±РѕР№ уникальное учебное и справочное РїРѕСЃРѕР±ие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий DelphiВ».Р' книге РїРѕРґСЂРѕР±но рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием. Р

Джулиан М. Бакнелл

Программирование, программы, базы данных