Ruby Language
Klasser
Sök…
Syntax
- klassnamn
- # någon kod som beskriver klassbeteendet
- slutet
Anmärkningar
Klassnamn i Ruby är konstanter, så den första bokstaven borde vara en stor bokstav.
class Cat # correct
end
class dog # wrong, throws an error
end
Skapa en klass
Du kan definiera en ny klass med class
nyckelord.
class MyClass
end
När den har definierats kan du skapa en ny instans med .new
metoden
somevar = MyClass.new
# => #<MyClass:0x007fe2b8aa4a18>
Konstruktör
En klass kan bara ha en konstruktör, det vill säga en metod som kallas initialize
. Metoden startas automatiskt när en ny instans av klassen skapas.
class Customer
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
sarah.name #=> 'Sarah'
Klass- och instansvariabler
Det finns flera speciella variabeltyper som en klass kan använda för att lättare dela data.
Instansvariabler, föregående av @
. De är användbara om du vill använda samma variabel på olika metoder.
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
Klassvariabel, föregående av @@
. De innehåller samma värden i alla instanser av en klass.
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
Globala variabler, föregående av $
. Dessa är tillgängliga var som helst för programmet, så se till att använda dem klokt.
$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
Få åtkomst till instansvariabler med getters och seters
Vi har tre metoder:
-
attr_reader
: används för att tillåtaread
av variabeln utanför klassen. -
attr_writer
: används för att tillåta ändring av variabeln utanför klassen. -
attr_accessor
: kombinerar båda metoderna.
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
Observera att parametrarna är symboler. detta fungerar genom att skapa en metod.
class Cat
attr_accessor :breed
end
Är i princip samma som:
class Cat
def breed
@breed
end
def breed= value
@breed = value
end
end
Åtkomstnivåer
Ruby har tre åtkomstnivåer. De är public
, private
och protected
.
Metoder som följer de private
eller protected
nyckelorden definieras som sådana. Metoder som kommer före dessa är implicit public
metoder.
Offentliga metoder
En offentlig metod ska beskriva beteendet hos objektet som skapas. Dessa metoder kan kallas utanför det skapade objektets räckvidd.
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
Dessa metoder är offentliga rubinmetoder, de beskriver beteendet för att initialisera en ny katt och beteendet för talmetoden.
public
nyckelord är onödigt, men kan användas för att undvika private
eller protected
def MyClass
def first_public_method
end
private
def private_method
end
public
def second_public_method
end
end
Privata metoder
Privata metoder är inte tillgängliga utanför objektet. De används internt av objektet. Använda kattexemplet igen:
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">
Som ni kan se i exemplet ovan har den nyskapade Cat objekt tillgång till calculate_cat_age
metoden internt. Vi tilldelar variabeln age
till följd av att köra privata calculate_cat_age
metod som skriver ut namn och ålder för katten att konsolen.
När vi försöker ringa calculate_cat_age
metoden utanför my_cat
objektet får vi en NoMethodError
eftersom det är privat. Förstår?
Skyddade metoder
Skyddade metoder liknar mycket privata metoder. De kan inte nås utanför objektet på samma sätt som privata metoder inte kan vara. Men med hjälp av self
ruby-metoden kan skyddade metoder kallas inom ramen för ett objekt av samma typ.
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>
Du kan se att vi har lagt till en åldersparameter till kattklassen och skapat tre nya kattobjekt med namn och ålder. Vi kommer att kalla own_age
för att jämföra åldern hos våra kattobjekt.
cat1 == cat2
=> false
cat1 == cat3
=> true
Titta på det, vi kunde hämta cat1s ålder med den skyddade metoden self.own_age
och jämföra den mot cat2: s ålder genom att ringa cat2.own_age
inuti cat1.
Klassmetoder
Klasserna har tre typer av metoder: instans, singleton och klassmetoder.
Instansmetoder
Det här är metoder som kan kallas från en instance
av klassen.
class Thing
def somemethod
puts "something"
end
end
foo = Thing.new # create an instance of the class
foo.somemethod # => something
Klassmetod
Dessa är statiska metoder, dvs de kan åberopas på klassen och inte på en instansering av den klassen.
class Thing
def Thing.hello(name)
puts "Hello, #{name}!"
end
end
Det motsvarar att använda self
i stället för klassnamnet. Följande kod motsvarar koden ovan:
class Thing
def self.hello(name)
puts "Hello, #{name}!"
end
end
Åkalla metoden genom att skriva
Thing.hello("John Doe") # prints: "Hello, John Doe!"
Singleton-metoder
Dessa är endast tillgängliga för specifika instanser i klassen, men inte för alla.
# 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>
Både singleton
och class
kallas eigenclass
es. I grund och botten, vad rubin gör är att skapa en anonym klass som har sådana metoder så att den inte stör de instanser som skapas.
Ett annat sätt att göra detta är av class <<
-konstruktören. Till exempel:
# 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"
Dynamisk klassskapning
Klasser kan skapas dynamiskt genom användning av Class.new
.
# create a new class dynamically
MyClass = Class.new
# instantiate an object of type MyClass
my_class = MyClass.new
I exemplet ovan skapas en ny klass och tilldelas konstant MyClass
. Denna klass kan instanseras och användas precis som alla andra klasser.
Metoden Class.new
accepterar en Class
som blir superklass för den dynamiskt skapade klassen.
# 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
Metoden Class.new
accepterar också ett block. Blockets sammanhang är den nyskapade klassen. Detta gör det möjligt att definiera metoder.
Duck =
Class.new do
def quack
'Quack!!'
end
end
# instantiate an object of type Duck
duck = Duck.new
duck.quack # 'Quack!!'
Nytt, allokera och initiera
På många språk skapas nya instanser av en klass med ett speciellt new
nyckelord. I Ruby används också new
för att skapa instanser av en klass, men det är inte ett nyckelord; istället är det en statisk / klassmetod som inte skiljer sig från någon annan statisk / klassmetod. Definitionen är ungefär denna:
class MyClass
def self.new(*args)
obj = allocate
obj.initialize(*args) # oversimplied; initialize is actually private
obj
end
end
allocate
utför den verkliga "magin" att skapa en oinitialiserad instans av klassen
Observera också att returvärdet för initialize
kastas och obj returneras istället. Detta gör det omedelbart klart varför du kan koda din initieringsmetod utan att oroa dig för att återvända self
i slutet.
Den "normala" new
metoden som alla klasser får från Class
fungerar som ovan, men det är möjligt att omdefiniera den du vill, eller definiera alternativ som fungerar annorlunda. Till exempel:
class MyClass
def self.extraNew(*args)
obj = allocate
obj.pre_initialize(:foo)
obj.initialize(*args)
obj.post_initialize(:bar)
obj
end
end