Ruby Language
Classi
Ricerca…
Sintassi
- nome della classe
- # Qualche codice che descrive il comportamento della classe
- fine
Osservazioni
I nomi delle classi in Ruby sono Costanti, quindi la prima lettera dovrebbe essere una maiuscola.
class Cat # correct
end
class dog # wrong, throws an error
end
Creare una classe
Puoi definire una nuova classe usando la parola chiave class
.
class MyClass
end
Una volta definiti, è possibile creare una nuova istanza utilizzando il .new
metodo
somevar = MyClass.new
# => #<MyClass:0x007fe2b8aa4a18>
Costruttore
Una classe può avere un solo costruttore, ovvero un metodo chiamato initialize
. Il metodo viene automaticamente richiamato quando viene creata una nuova istanza della classe.
class Customer
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
sarah.name #=> 'Sarah'
Classi e variabili di istanza
Esistono diversi tipi di variabili speciali che una classe può utilizzare per condividere più facilmente i dati.
Variabili di istanza, precedute da @
. Sono utili se si desidera utilizzare la stessa variabile con metodi diversi.
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
Variabile di classe, preceduta da @@
. Contengono gli stessi valori su tutte le istanze di una classe.
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
Variabili globali, precedute da $
. Questi sono disponibili ovunque per il programma, quindi assicurati di usarli con saggezza.
$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
Accesso alle variabili di istanza con getter e setter
Abbiamo tre metodi:
-
attr_reader
: utilizzato per consentire laread
della variabile al di fuori della classe. -
attr_writer
: usato per consentire la modifica della variabile al di fuori della classe. -
attr_accessor
: combina entrambi i metodi.
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
Si noti che i parametri sono simboli. questo funziona creando un metodo.
class Cat
attr_accessor :breed
end
È fondamentalmente lo stesso di:
class Cat
def breed
@breed
end
def breed= value
@breed = value
end
end
Livelli di accesso
Ruby ha tre livelli di accesso. Sono public
, private
e protected
.
I metodi che seguono le parole chiave private
o protected
sono definiti come tali. I metodi che precedono questi sono metodi implicitamente public
.
Metodi pubblici
Un metodo pubblico dovrebbe descrivere il comportamento dell'oggetto che si sta creando. Questi metodi possono essere richiamati dall'esterno dell'oggetto creato.
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
Questi metodi sono metodi ruby pubblici, descrivono il comportamento per l'inizializzazione di un nuovo gatto e il comportamento del metodo speak.
public
parola chiave public
non è necessaria, ma può essere utilizzata per sfuggire a private
o protected
def MyClass
def first_public_method
end
private
def private_method
end
public
def second_public_method
end
end
Metodi privati
I metodi privati non sono accessibili dall'esterno dell'oggetto. Sono usati internamente dall'oggetto. Usando di nuovo l'esempio del gatto:
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">
Come puoi vedere nell'esempio sopra, l'oggetto Cat appena creato ha accesso al metodo calculate_cat_age
internamente. Assegniamo l' age
variabile al risultato dell'esecuzione del metodo private calculate_cat_age
che stampa il nome e l'età del gatto sulla console.
Quando proviamo a chiamare il metodo calculate_cat_age
dall'esterno dell'oggetto my_cat
, riceviamo un NoMethodError
perché è privato. Prendilo?
Metodi protetti
I metodi protetti sono molto simili ai metodi privati. Non è possibile accedere al di fuori dell'istanza dell'oggetto nello stesso modo in cui i metodi privati non possono essere. Tuttavia, usando il metodo self
ruby, i metodi protetti possono essere chiamati all'interno del contesto di un oggetto dello stesso tipo.
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>
Puoi vedere che abbiamo aggiunto un parametro età alla classe cat e creato tre nuovi oggetti gatto con il nome e l'età. Chiameremo il metodo protetto own_age
per confrontare l'età dei nostri oggetti gatto.
cat1 == cat2
=> false
cat1 == cat3
=> true
Guardate questo, siamo stati in grado di recuperare l'età di cat1 usando il metodo protetto self.own_age
e confrontarlo con l'età di cat2.own_age
chiamando cat2.own_age
all'interno di cat1.
Tipi di metodi di classe
Le classi hanno 3 tipi di metodi: istanza, singleton e metodi di classe.
Metodi di istanza
Questi sono metodi che possono essere chiamati da instance
della classe.
class Thing
def somemethod
puts "something"
end
end
foo = Thing.new # create an instance of the class
foo.somemethod # => something
Metodo di classe
Questi sono metodi statici, cioè possono essere richiamati sulla classe e non su un'istanza di quella classe.
class Thing
def Thing.hello(name)
puts "Hello, #{name}!"
end
end
È equivalente usare self
al posto del nome della classe. Il seguente codice è equivalente al codice sopra:
class Thing
def self.hello(name)
puts "Hello, #{name}!"
end
end
Invoca il metodo scrivendo
Thing.hello("John Doe") # prints: "Hello, John Doe!"
Metodi Singleton
Questi sono disponibili solo per istanze specifiche della classe, ma non per tutti.
# 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>
Entrambi i metodi singleton
e class
sono chiamati eigenclass
es. Fondamentalmente, ciò che ruby fa è creare una classe anonima che contiene tali metodi in modo che non interferisca con le istanze che vengono create.
Un altro modo per farlo è il costruttore della class <<
. Per esempio:
# 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"
Creazione di classi dinamiche
Le classi possono essere create dinamicamente attraverso l'uso di Class.new
.
# create a new class dynamically
MyClass = Class.new
# instantiate an object of type MyClass
my_class = MyClass.new
Nell'esempio sopra, una nuova classe viene creata e assegnata alla costante MyClass
. Questa classe può essere istanziata e utilizzata come qualsiasi altra classe.
Il metodo Class.new
accetta una Class
che diventerà la superclasse della classe creata dinamicamente.
# 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
Il metodo Class.new
accetta anche un blocco. Il contesto del blocco è la classe appena creata. Ciò consente di definire metodi.
Duck =
Class.new do
def quack
'Quack!!'
end
end
# instantiate an object of type Duck
duck = Duck.new
duck.quack # 'Quack!!'
Nuovo, allocare e inizializzare
In molte lingue, vengono create nuove istanze di una classe utilizzando una new
parola chiave speciale. In Ruby, new
viene anche usato per creare istanze di una classe, ma non è una parola chiave; invece, è un metodo statico / di classe, non diverso da qualsiasi altro metodo statico / di classe. La definizione è all'incirca questa:
class MyClass
def self.new(*args)
obj = allocate
obj.initialize(*args) # oversimplied; initialize is actually private
obj
end
end
allocate
esegue la vera 'magia' di creare un'istanza non inizializzata della classe
Si noti inoltre che il valore di ritorno di initialize
viene scartato e invece viene restituito obj. Questo rende immediatamente chiaro il motivo per cui puoi codificare il tuo metodo di inizializzazione senza preoccuparti di restituire te self
alla fine.
Il new
metodo "normale" che tutte le classi ottengono da Class
funziona come sopra, ma è possibile ridefinirlo come più ti piace o definire alternative che funzionano in modo diverso. Per esempio:
class MyClass
def self.extraNew(*args)
obj = allocate
obj.pre_initialize(:foo)
obj.initialize(*args)
obj.post_initialize(:bar)
obj
end
end