В Ruby есть множество встроенных классов, и вы сами можете определять новые.
Для определения нового класса применяется такая конструкция:
. class ClassName
# . . .
end
Само имя класса - это глобальная константа, поэтому оно должно начинаться
с прописной буквы. Определение класса может содержать константы, переменные
класса, методы класса, переменные экземпляра и методы экземпляра. Данные
уровня класса доступны всем объектам этого класса, тогда как данные уровня экземпляра
доступны только одному объекту.
Попутное замечание: строго говоря, классы в Ruby не имеют имен. «Ямя»
класса - это всего лишь константа, ссылающаяся на объект типа class (поскольку
в Ruby class - это класс). Ясно, что на один и тот же класс могут ссылаться
несколько констант, и их можно присваивать переменным точно так же, как мы
поступаем с любыми другими объектами (поскольку в Ruby Class - это объект).
Если вы немного запутались, не расстраивайтесь. Удобства ради новичок может
считать, что в Ruby имя класса - то же самое, что в С++.
Вот как определяется простой класс:
class Friend
@@myname = "Эндрю" # переменная класса
def initialize(name, sex, phone)
Sname, @sex, @phone = name, sex, phone
# Это переменные экземпляра
end
def hello # метод экземпляра
puts "Привет, я #{@name}."
end
def Friend.our_common_friend # метод класса
puts "Все мы друзья #{@@myname}."
end
end
fl = Friend.new("Сюзанна","F","555-0123")
f2 = Friend.new("Том","M","555-4567")
fl.hello ' # Привет, я Сюзанна,
f2.hello # Привет, я Том.
Friend.our_common_friend # Все мы друзья Эндрю.
Поскольку данные уровня класса доступны во всем классе, их можно инициализировать
в момент определения класса. Если определен метод с именем
initialize, то гарантируется, что он будет вызван сразу после выделения памяти
для объекта. Этот метод похож на традиционный конструктор, но не выполняет
выделения памяти. Память выделяется методом new, а освобождается неявно
сборщиком мусора.
Теперь взгляните на следующий фрагмент, обращая особое внимание на методы
getmyvar, setmyvar И myvar=:
class MyClass
NAME = "Class Name" # константа класса
@@count =0 # инициализировать переменную класса
def initialize # вызывается после выделения памяти для объекта
@@count += 1
@myvar =10
end
def MyClass.getcount # метод класса
@@count
end
# переменная класса
def getcount
@@count
end
# экземпляр возвращает переменную класса!
# переменная класса
def getmyvar
@myvar
end
# метод экземпляра
# переменная экземпляра
def setmyvar(val)
@myvar = val
end
def myvar=(val)
@myvar = val
end
end
# метод экземпляра устанавливает Smyvar
# другой способ установить Smyvar
foo = MyClass.new # Smyvar равно 10
foo.setmyvar 20 # Smyvar равно 20
foo.myvar = 30 # Smyvar равно 30
Здесь мы видим, что getmyvar возвращает значение переменной Smyvar, а
setmyvar устанавливает его. (Многие программисты говорят о методах чтения и
установки). Все это работает, но не является характерным способом действий в
Ruby. Метод myvar= похож на перегруженный оператор присваивания (хотя, строго
говоря, таковым не является); это более удачная альтернатива setmyvar, но есть
способ еще лучше.
Класс Module содержит методы attr, attr_accessor, attr_reader и attr_writer.
Ими можно пользоваться (передавая символы в качестве параметров) для автоматизации
управления доступом к данным экземпляра. Например, все три метода
getmyvar, setmyvar и myvar= можно заменить одной строкой в определении класса:
attr_accessor :myvar
При этом создается метод myvar, который возвращает значение Smyvar, и метод
myvar=, который позволяет изменить значение той же переменной. Методы attr_
reader и attr_writer создают соответственно версии методов доступа к атрибуту
для чтения и для изменения.
Внутри методов экземпляра, определенных в классе, можно при необходимости
пользоваться переменной self. Это просто ссылка на объект, от имени которого
вызван метод экземпляра.
Для управления видимостью методов класса можно пользоваться модификаторами
private, protected и public. (Переменные экземпляра всегда закрыты, обращаться
к ним извне класса можно только с помощью методов доступа.) Каждый
модификатор принимает в качестве параметра символ, например : f оо, а если он
опущен, то действие модификатора распространяется на все последующие определения
в классе. Пример:
class MyClass
def methodl
# ...
end
def method2
# ...
end
def method3
# . . .
end
private :methodl
public
:method2
protected :method3
private
def my_method
# ...
end
def another_method
# ...
end
end.
В этом классе метод methodl закрытый, method2 открытый, a method3 защищенный.
Поскольку далее вызывается метод private без параметров, то методы ту_
method и another_method будут закрытыми.
Уровень доступа public не нуждается в объяснениях, он не налагает никаких
ограничений ни на доступ к методу, ни на его видимость. Уровень private означает, что метод доступен исключительно внутри класса или его подклассов и может вызываться только в «функциональной форме» от имени self, причем вызывающий объект может указываться явно или подразумеваться неявно. Уровень
protected означает, что метод вызывается только внутри класса, но, в отличие от закрытого метода, не обязательно от имени self.
По умолчанию все определенные в классе методы открыты. Исключение составляет
лишь initialize. Методы, определенные на верхнем уровне программы,
тоже по умолчанию открыты. Если они объявлены закрытыми, то могут вызываться
только в функциональной форме (как, например, методы, определенные в классе
Object).
Классы в Ruby сами являются объектами - экземплярами метакласса class.
Классы в этом языке всегда конкретны, абстрактных классов не существует. Однако
теоретически можно реализовать и абстрактные классы, если вам это для чего-
то понадобится.
Класс object является корнем иерархии. Он предоставляет все методы, определенные
во встроенном модуле Kernel.
Чтобы создать класс, наследующий другому классу, нужно поступить следующим
образом:
class MyClass < OtherClass
# ...
end
Помимо использования встроенных методов, вполне естественно определить
и собственные либо переопределить унаследованные. Если определяемый метод
имеет то же имя, что и существующий, то старый метод замещается. Если новый
метод должен обратиться к замещенному им «родительскому» методу (так бывает
часто), можно воспользоваться ключевым словом super.
Перегрузка операторов, строго говоря, не является неотъемлемой особенностью
ООП, но этот механизм знаком программистам на С++ и некоторых других
языках. Поскольку большинство операторов в Ruby так или иначе являются методами,
то не должен вызывать удивления тот факт, что их можно переопределять
или определять в пользовательских классах. Переопределять семантику оператора
в существующем классе редко имеет смысл, зато в новых классах определение
операторов - обычное дело.
Можно создавать синонимы методов. Для этого внутри определения класса
предоставляется такой синтаксис:
alias newname oldname
Число параметров будет таким же, как для старого имени, и вызываться метод-
синоним будет точно так же. Обратите внимание на отсутствие запятой; alias -
это не имя метода, а ключевое слово. Существует метод с именем alias_method,
который ведет себя аналогично, но в случае его применения параметры должны
разделяться запятыми, как и для любого другого метода.
