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:

  1. attr_reader : służy do read zmiennej poza klasą.
  2. attr_writer : służy do modyfikowania zmiennej poza klasą.
  3. 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


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow