Ruby Language
Классы
Поиск…
Синтаксис
- имя класса
- # некоторый код, описывающий поведение класса
- конец
замечания
Названия классов в Ruby - это константы, поэтому первая буква должна быть капиталом.
class Cat # correct
end
class dog # wrong, throws an error
end
Создание класса
Вы можете определить новый класс, используя ключевое слово class
.
class MyClass
end
После определения вы можете создать новый экземпляр, используя метод .new
somevar = MyClass.new
# => #<MyClass:0x007fe2b8aa4a18>
Конструктор
Класс может иметь только один конструктор, то есть метод, называемый initialize
. Метод автоматически вызывается, когда создается новый экземпляр класса.
class Customer
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
sarah.name #=> 'Sarah'
Переменные класса и экземпляра
Существует несколько специальных типов переменных, которые класс может использовать для более простого обмена данными.
Переменные экземпляра, которым предшествует @
. Они полезны, если вы хотите использовать одну и ту же переменную в разных методах.
class Person
def initialize(name, age)
my_age = age # local variable, will be destroyed at end of constructor
@name = name # instance variable, is only destroyed when the object is
end
def some_method
puts "My name is #{@name}." # we can use @name with no problem
end
def another_method
puts "My age is #{my_age}." # this will not work!
end
end
mhmd = Person.new("Mark", 23)
mhmd.some_method #=> My name is Mark.
mhmd.another_method #=> throws an error
Переменная класса, которой предшествует @@
. Они содержат одинаковые значения во всех экземплярах класса.
class Person
@@persons_created = 0 # class variable, available to all objects of this class
def initialize(name)
@name = name
# modification of class variable persists across all objects of this class
@@persons_created += 1
end
def how_many_persons
puts "persons created so far: #{@@persons_created}"
end
end
mark = Person.new("Mark")
mark.how_many_persons #=> persons created so far: 1
helen = Person.new("Helen")
mark.how_many_persons #=> persons created so far: 2
helen.how_many_persons #=> persons created so far: 2
# you could either ask mark or helen
Глобальные переменные, которым предшествует $
. Они доступны в любом месте программы, поэтому обязательно используйте их с умом.
$total_animals = 0
class Cat
def initialize
$total_animals += 1
end
end
class Dog
def initialize
$total_animals += 1
end
end
bob = Cat.new()
puts $total_animals #=> 1
fred = Dog.new()
puts $total_animals #=> 2
Доступ к переменным экземпляра с помощью геттеров и сеттеров
У нас есть три метода:
-
attr_reader
: используется дляread
переменной вне класса. -
attr_writer
: используется для модификации переменной вне класса. -
attr_accessor
: объединяет оба метода.
class Cat
attr_reader :age # you can read the age but you can never change it
attr_writer :name # you can change name but you are not allowed to read
attr_accessor :breed # you can both change the breed and read it
def initialize(name, breed)
@name = name
@breed = breed
@age = 2
end
def speak
puts "I'm #{@name} and I am a #{@breed} cat"
end
end
my_cat = Cat.new("Banjo", "birman")
# reading values:
my_cat.age #=> 2
my_cat.breed #=> "birman"
my_cat.name #=> Error
# changing values
my_cat.age = 3 #=> Error
my_cat.breed = "sphynx"
my_cat.name = "Bilbo"
my_cat.speak #=> I'm Bilbo and I am a sphynx cat
Обратите внимание, что параметры являются символами. это работает путем создания метода.
class Cat
attr_accessor :breed
end
В основном это то же самое, что:
class Cat
def breed
@breed
end
def breed= value
@breed = value
end
end
Уровни доступа
Ruby имеет три уровня доступа. Они являются public
, private
и protected
.
Методы, которые следуют за private
или protected
ключевыми словами, определяются как таковые. Методы, которые появляются перед ними, являются неявно public
методами.
Общественные методы
Открытый метод должен описывать поведение создаваемого объекта. Эти методы можно вызывать из-за пределов созданного объекта.
class Cat
def initialize(name)
@name = name
end
def speak
puts "I'm #{@name} and I'm 2 years old"
end
...
end
new_cat = Cat.new("garfield")
#=> <Cat:0x2321868 @name="garfield">
new_cat.speak
#=> I'm garfield and I'm 2 years old
Эти методы являются общедоступными рубиновыми методами, они описывают поведение для инициализации нового кота и поведение метода речи.
public
ключевое слово не нужно, но может использоваться для выхода из private
или protected
def MyClass
def first_public_method
end
private
def private_method
end
public
def second_public_method
end
end
Частные методы
Частные методы недоступны извне объекта. Они используются внутри объекта. Повторное использование примера cat:
class Cat
def initialize(name)
@name = name
end
def speak
age = calculate_cat_age # here we call the private method
puts "I'm #{@name} and I'm #{age} years old"
end
private
def calculate_cat_age
2 * 3 - 4
end
end
my_cat = Cat.new("Bilbo")
my_cat.speak #=> I'm Bilbo and I'm 2 years old
my_cat.calculate_cat_age #=> NoMethodError: private method `calculate_cat_age' called for #<Cat:0x2321868 @name="Bilbo">
Как вы можете видеть в приведенном выше примере, только что созданный объект Cat имеет доступ к методу calculate_cat_age
внутри. Мы присваиваем переменный age
в результате запуска частного calculate_cat_age
метода , который печатает имя и возраст кошки на консоль.
Когда мы пытаемся вызвать метод calculate_cat_age
извне объекта my_cat
, мы получаем NoMethodError
потому что он частный. Возьми?
Защищенные методы
Защищенные методы очень похожи на частные методы. Они не могут быть доступны вне экземпляра объекта так же, как частные методы не могут быть. Однако, используя метод self
ruby, защищенные методы могут быть вызваны в контексте объекта того же типа.
class Cat
def initialize(name, age)
@name = name
@age = age
end
def speak
puts "I'm #{@name} and I'm #{@age} years old"
end
# this == method allows us to compare two objects own ages.
# if both Cat's have the same age they will be considered equal.
def ==(other)
self.own_age == other.own_age
end
protected
def own_age
self.age
end
end
cat1 = Cat.new("ricky", 2)
=> #<Cat:0x007fe2b8aa4a18 @name="ricky", @age=2>
cat2 = Cat.new("lucy", 4)
=> #<Cat:0x008gfb7aa6v67 @name="lucy", @age=4>
cat3 = Cat.new("felix", 2)
=> #<Cat:0x009frbaa8V76 @name="felix", @age=2>
Вы можете видеть, что мы добавили параметр возраста в класс cat и создали три новых объекта кошки с именем и возрастом. Мы будем называть метод own_age
чтобы сравнить возраст наших объектов кошки.
cat1 == cat2
=> false
cat1 == cat3
=> true
Посмотрите на это, мы смогли восстановить возраст cat1 с помощью метода self.own_age
protected и сравнить его с возрастом cat2, вызвав cat2.own_age
внутри cat1.
Типы типов классов
Классы имеют 3 типа методов: instance, singleton и class.
Методы экземпляра
Это методы, которые можно вызывать из instance
класса.
class Thing
def somemethod
puts "something"
end
end
foo = Thing.new # create an instance of the class
foo.somemethod # => something
Метод класса
Это статические методы, т. Е. Они могут быть вызваны в классе, а не на экземпляре этого класса.
class Thing
def Thing.hello(name)
puts "Hello, #{name}!"
end
end
Это эквивалентно использованию self
вместо имени класса. Следующий код эквивалентен приведенному выше коду:
class Thing
def self.hello(name)
puts "Hello, #{name}!"
end
end
Вызовите метод, написав
Thing.hello("John Doe") # prints: "Hello, John Doe!"
Методы Singleton
Они доступны только для определенных экземпляров класса, но не для всех.
# create an empty class
class Thing
end
# two instances of the class
thing1 = Thing.new
thing2 = Thing.new
# create a singleton method
def thing1.makestuff
puts "I belong to thing one"
end
thing1.makestuff # => prints: I belong to thing one
thing2.makestuff # NoMethodError: undefined method `makestuff' for #<Thing>
Оба метода singleton
и class
называются eigenclass
es. В основном, что Ruby делает, это создать анонимный класс, который содержит такие методы, чтобы он не мешал созданным экземплярам.
Другой способ сделать это - конструктор class <<
. Например:
# a class method (same as the above example)
class Thing
class << self # the anonymous class
def hello(name)
puts "Hello, #{name}!"
end
end
end
Thing.hello("sarah") # => Hello, sarah!
# singleton method
class Thing
end
thing1 = Thing.new
class << thing1
def makestuff
puts "I belong to thing one"
end
end
thing1.makestuff # => prints: "I belong to thing one"
Создание динамического класса
Классы могут создаваться динамически с помощью Class.new
.
# create a new class dynamically
MyClass = Class.new
# instantiate an object of type MyClass
my_class = MyClass.new
В приведенном выше примере создается новый класс и назначается константе MyClass
. Этот класс может быть создан и использован как любой другой класс.
Метод Class.new
принимает Class
который станет суперклассом динамически созданного класса.
# dynamically create a class that subclasses another
Staffy = Class.new(Dog)
# instantiate an object of type Staffy
lucky = Staffy.new
lucky.is_a?(Staffy) # true
lucky.is_a?(Dog) # true
Метод Class.new
также принимает блок. Контекст блока - это новый класс. Это позволяет определять методы.
Duck =
Class.new do
def quack
'Quack!!'
end
end
# instantiate an object of type Duck
duck = Duck.new
duck.quack # 'Quack!!'
Создать, выделить и инициализировать
На многих языках новые экземпляры класса создаются с использованием специального new
ключевого слова. В Ruby new
также используется для создания экземпляров класса, но это не ключевое слово; вместо этого это метод static / class, отличный от любого другого метода static / class. Это примерно так:
class MyClass
def self.new(*args)
obj = allocate
obj.initialize(*args) # oversimplied; initialize is actually private
obj
end
end
allocate
выполняет реальную «магию» создания неинициализированного экземпляра класса
Также обратите внимание, что возвращаемое значение initialize
отбрасывается, и вместо него возвращается obj. Это сразу позволяет понять, почему вы можете кодировать свой метод инициализации, не беспокоясь о возврате self
в конце.
«Обычный» new
метод, который все классы получают из Class
работает, как описано выше, но можно переопределить его, как вам нравится, или определить альтернативы, которые работают по-другому. Например:
class MyClass
def self.extraNew(*args)
obj = allocate
obj.pre_initialize(:foo)
obj.initialize(*args)
obj.post_initialize(:bar)
obj
end
end