Ruby Language
Klasy
Szukaj…
Składnia
- Nazwa klasy
- #some kod opisujący zachowanie klasy
- koniec
Uwagi
Nazwy klas w Rubim są stałymi, więc pierwsza litera powinna być wielka.
class Cat # correct
end
class dog # wrong, throws an error
end
Tworzenie klasy
Możesz zdefiniować nową klasę za pomocą słowa kluczowego class
.
class MyClass
end
Po zdefiniowaniu można utworzyć nową instancję za pomocą metody .new
somevar = MyClass.new
# => #<MyClass:0x007fe2b8aa4a18>
Konstruktor
Klasa może mieć tylko jednego konstruktora, czyli metodę o nazwie initialize
. Metoda jest wywoływana automatycznie po utworzeniu nowej instancji klasy.
class Customer
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
sarah.name #=> 'Sarah'
Zmienne klas i instancji
Istnieje kilka specjalnych typów zmiennych, które klasa może wykorzystać do łatwiejszego udostępniania danych.
Zmienne wystąpienia poprzedzone @
. Są przydatne, jeśli chcesz użyć tej samej zmiennej w różnych metodach.
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
Zmienna klasy, poprzedzona @@
. Zawierają te same wartości we wszystkich instancjach klasy.
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
Zmienne globalne, poprzedzone znakiem $
. Są one dostępne w dowolnym miejscu programu, więc używaj ich mądrze.
$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
Dostęp do zmiennych instancji za pomocą metod pobierających i ustawiających
Mamy trzy metody:
-
attr_reader
: służy doread
zmiennej poza klasą. -
attr_writer
: służy do modyfikowania zmiennej poza klasą. -
attr_accessor
: łączy obie metody.
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
Pamiętaj, że parametry są symbolami. działa to poprzez utworzenie metody.
class Cat
attr_accessor :breed
end
Jest w zasadzie taki sam jak:
class Cat
def breed
@breed
end
def breed= value
@breed = value
end
end
Poziomy dostępu
Ruby ma trzy poziomy dostępu. Są public
, private
i protected
.
Metody następujące po słowach private
lub protected
są zdefiniowane jako takie. Metody, które występują przed nimi, są domyślnie metodami public
.
Metody publiczne
Metoda publiczna powinna opisywać zachowanie tworzonego obiektu. Te metody można wywoływać spoza zakresu tworzonego obiektu.
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
Te metody są publicznymi metodami ruby, opisują zachowanie inicjowania nowego kota i zachowanie metody speak.
public
słowo kluczowe jest niepotrzebne, ale może być użyte do ucieczki od private
lub protected
def MyClass
def first_public_method
end
private
def private_method
end
public
def second_public_method
end
end
Metody prywatne
Metody prywatne nie są dostępne z zewnątrz obiektu. Są one używane wewnętrznie przez obiekt. Korzystając z przykładu kota ponownie:
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">
Jak widać na powyższym przykładzie, nowo utworzony obiekt Cat ma dostęp do calculate_cat_age
metody wewnętrznie. Przypisujemy zmiennej age
do wyniku prowadzenia prywatnej calculate_cat_age
metodę, która drukuje nazwę i wiek kota do konsoli.
Kiedy staramy i wywołać calculate_cat_age
metody spoza my_cat
obiektu, otrzymujemy NoMethodError
bo to prywatny. Zdobyć?
Metody chronione
Metody chronione są bardzo podobne do metod prywatnych. Nie można uzyskać do nich dostępu poza wystąpieniem obiektu w taki sam sposób, jak nie mogą być dostępne metody prywatne. Jednak przy użyciu metody self
ruby metody chronione można wywoływać w kontekście obiektu tego samego typu.
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>
Możesz zobaczyć, że dodaliśmy parametr wieku do klasy cat i stworzyliśmy trzy nowe obiekty cat o nazwie i wieku. own_age
metodę chronioną own_age
, aby porównać wiek naszych obiektów kotów.
cat1 == cat2
=> false
cat1 == cat3
=> true
Spójrz na to, byliśmy w stanie odzyskać wiek kota za pomocą metody chronionej self.own_age
i porównać go z wiekiem cat2.own_age
wywołując cat2.own_age
wewnątrz cat1.
Typy metod klas
Klasy mają 3 typy metod: instancja, singleton i metody klas.
Metody instancji
Są to metody, które można wywołać z instance
klasy.
class Thing
def somemethod
puts "something"
end
end
foo = Thing.new # create an instance of the class
foo.somemethod # => something
Metoda klasowa
Są to metody statyczne, tzn. Można je wywoływać w klasie, a nie w instancji tej klasy.
class Thing
def Thing.hello(name)
puts "Hello, #{name}!"
end
end
Jest to równoważne z użyciem self
zamiast nazwy klasy. Poniższy kod jest równoważny powyższemu kodowi:
class Thing
def self.hello(name)
puts "Hello, #{name}!"
end
end
Wywołaj metodę pisząc
Thing.hello("John Doe") # prints: "Hello, John Doe!"
Metody Singleton
Są one dostępne tylko dla określonych instancji klasy, ale nie dla wszystkich.
# 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>
Zarówno metody singleton
i class
nazywane są eigenclass
es. Zasadniczo ruby tworzy anonimową klasę, która przechowuje takie metody, aby nie kolidowała z tworzonymi instancjami.
Innym sposobem na to jest konstruktor class <<
. Na przykład:
# 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"
Dynamiczne tworzenie klas
Klasy można tworzyć dynamicznie za pomocą Class.new
.
# create a new class dynamically
MyClass = Class.new
# instantiate an object of type MyClass
my_class = MyClass.new
W powyższym przykładzie tworzona jest nowa klasa i przypisywana do stałej MyClass
. Ta klasa może być utworzona i używana tak jak każda inna klasa.
Metoda Class.new
akceptuje Class
która stanie się Class.new
dynamicznie tworzonej klasy.
# 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
Metoda Class.new
akceptuje również blok. Kontekstem bloku jest nowo utworzona klasa. Umożliwia to zdefiniowanie metod.
Duck =
Class.new do
def quack
'Quack!!'
end
end
# instantiate an object of type Duck
duck = Duck.new
duck.quack # 'Quack!!'
Nowe, przydziel i zainicjuj
W wielu językach nowe wystąpienia klasy są tworzone za pomocą specjalnego new
słowa kluczowego. W Ruby new
jest również używany do tworzenia instancji klasy, ale nie jest słowem kluczowym; zamiast tego jest to metoda statyczna / klasowa, nie różni się niczym od żadnej innej metody statycznej / klasowej. Definicja jest mniej więcej następująca:
class MyClass
def self.new(*args)
obj = allocate
obj.initialize(*args) # oversimplied; initialize is actually private
obj
end
end
allocate
wykonuje prawdziwą „magię” tworzenia niezainicjowanej instancji klasy
Zauważ też, że zwracana wartość initialize
jest odrzucana, a zamiast niej zwracana jest obj. To od razu wyjaśnia, dlaczego możesz zakodować swoją metodę inicjalizacji, nie martwiąc się o powrót self
na końcu.
„Normalna” new
metoda, którą wszystkie klasy uzyskują z Class
działa jak wyżej, ale można ją przedefiniować w dowolny sposób lub zdefiniować alternatywy, które działają inaczej. Na przykład:
class MyClass
def self.extraNew(*args)
obj = allocate
obj.pre_initialize(:foo)
obj.initialize(*args)
obj.post_initialize(:bar)
obj
end
end