Font: Font
1. Conceptualització
- Ruby és un llenguatge purament orientat a objectes, tot es veu com un objecte.
- Cada valor és un objecte, inclús les coses més simples: cadenes, nombres, booleans…
- Cada classe en sí mateix és un objecte que és una instància de la clase
class
. - La classe s’usa per a especificar la forma en d’un objecte i combina la representació de dades i els mètodes per a manipular aquestes dades en un paquet ordenat.
- Les dades i els mètodes s’anomenen membres de la classe.
2. Class
Quan definim una class
, definim un model per a un tipus de dades. Això no defineix realment cap dada, sinó que defineix el que vol dir el nom de classe, és a dir, en què consistirà un objecte de la classe i quines operacions es poden dur a terme en aquest objecte.
Una definició de classe comença amb la classe de paraula clau seguida del nom de la classe i està limitat amb un final.
class Box
code
end
El nom de la classe ha de començar per majúscula, i per convenció, els noms que contingen més d’una paraula s’executen juntament amb cada paraula majúscula i sense separar els caracters (CamelCase).
3. Objects
Una classe proporciona els plànols dels objectes, de manera que bàsicament es crea un objecte a partir d’una classe. Declarem objectes d’una classe mitjançant una nova paraula clau. Les declaracinos següents declaren dos objectes de la classe Box.
box1 = Box.new
box2 = Box.new
4. El mètode d’inicialització
El mètode d’inicialització és un mètode de classe Ruby estàndard i funcinoa gairebé de la mateixa manera que el mconstructura funciona en altres llenguatges de programació orientatats a objectes.
El mètode d’inicialització és útil quan volem inicialitzar algunes variables de classe en el moment de la creació d’objectes.
Aquest mètode pot prendre una llista de paràmetres i, com qualsevol altre mètode de Ruby, seria precedida per la paraula clau def
com es mostra a continuació:
class Box
def initialize(w,h)
@width, @height = w, h
end
end
5. Instance Variables
Les variables d’instància són tipus d’atributs de classe i es converteixen en propietats dels objectes quan els objectes es creen utilitzant la classe.
Els atributs de cada objecte s’assignen individualment i no comparteixen cap valor amb altres objectes.
S’hi accedeix mitjançant l’operador @
dins de la classe, però per accedir-hi fora de la classe utilitzem mètodes públics, que s’anomenen mètodes d’accés.
Si prenem la classe definida anteriorment, class Box
, llavors @width
i @height
s’on variables de class Box
.
class Box
def initialize(w,h)
# assign instance variables
@width, @height = w,h
end
end
6. Constructor Methods and Accessor Methods
Perquè les variables estiguen disponibles des de fora de la classe, s’han de definir dins dels accesor methods
, aquests mètodes accessoris també es coneixen com a getter methods
. L’exemple següent mostra l’ús de mètodes d’accés:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def printWidth
@width
end
def printHeight
@height
end
end
# create an object
box = Box.new(10, 20)
# use accessor methods
x = box.printWidth()
y = box.printHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
Output:
Width of the box is : 10
Height of the box is : 20
Igual que els mètodes accessoris, que s’utilitzen per accedir al valor de les variables, Ruby proporciona una manera d’establir els valors d’aquestes variables de fora de la classe mitjançant setter metthods
, que es defineixen a continuació:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# use setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
Output:
Width of the box is : 30
Height of the box is : 50
7. Instance Methods
Els mètodes d’instància també es defineixen de la mateixa manera que definim qualsevol altre mètode que utilitza la paraula clau def
i es poden utilitzar utilitzant una instància de classe només com es mostra a continuació.
La seva funcionalitat no es limita a accedir a les variables d’instància, sinó que també poden fer molt més segons el vostre requisit.
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
Output:
Area of the box is : 200
8. Class Methods and Variables
Les variables de classe són una variable que es comparteix entre totes les instàncies d’una classe. En altres paraules, hi ha una instància de la variable i s’hi accedeix per instàncies d’objectes. Les variables de classe són prefixades amb dos caràcters @
(@@
). S’ha d’inicialitzar una variable de classe dins de la definició de classe tal com es mostra a continuació.
Es defineix un mètode de classe utilitzant def self.methodname ()
, que acaba amb el delimitador final i s’anomenarà utilitzant el nom de la classe com a classname.methodname
tal com es mostra al següent exemple:
#!/usr/bin/ruby -w
class Box
# Initialize our class variables
@@count = 0
def initialize(w,h)
# assign instance avriables
@width, @height = w, h
@@count += 1
end
def self.printCount()
puts "Box count is : #@@count"
end
end
# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)
# call class method to print box count
Box.printCount()
9. Method to_s
Qualsevol classe que definiu ha de tenir un mètode d’instància to_s
per retornar una representació de cadena de l’objecte. A continuació es mostra un exemple simple per representar un objecte Box en termes d’amplada i altura:
#!/usr/bin/ruby -w
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# define to_s method
def to_s
"(w:#@width,h:#@height)" # string formatting of the object.
end
end
# create an object
box = Box.new(10, 20)
# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"
Output:
String representation of box is : (w:10,h:20)
10. Control d’accés
Ruby us ofereix tres nivells de protecció a nivell de mètodes d’instància, que poden ser públics, privats o protegits. Ruby no aplica cap control d’accés sobre variables d’instància i classe.
-
Mètodes públics: qualsevol persona pot trucar als mètodes públics. Els mètodes són públics per defecte excepte per inicialitzar, que sempre és privat.
-
Mètodes privats: no es pot accedir als mètodes privats ni, fins i tot, es poden veure des de fora de la classe. Només els mètodes de classe poden accedir als membres privats.
-
Mètodes protegits: un mètode protegit només pot ser invocat pels objectes de la classe que defineix i les seves subclasses. L’accés es manté a la família.
A continuació es mostra un exemple senzill per mostrar la sintaxi de tots els tres modificadors d’accés:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method by default it is public
def getArea
getWidth() * getHeight
end
# define private accessor methods
def getWidth
@width
end
def getHeight
@height
end
# make them private
private :getWidth, :getHeight
# instance method to print area
def printArea
@area = getWidth() * getHeight
puts "Big box area is : #@area"
end
# make it protected
protected :printArea
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
# try to call protected or methods
box.printArea()
Quan s’executa el codi anterior, es produeix el següent resultat. Aquí, el primer mètode es diu amb èxit, però el segon mètode ha donat un problema.
Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)
11. Herència de classe
Un dels conceptes més importants en la programació orientada a objectes és el de l’herència. L’herència ens permet definir una classe en termes d’una altra classe, cosa que facilita la creació i el manteniment d’una aplicació.
L’herència també ofereix l’oportunitat de reutilitzar la funcionalitat del codi i el ràpid temps d’implementació, però, lamentablement, Ruby no suporta múltiples nivells d’herència, però Ruby suporta mixins. Una barreja és com una implementació especialitzada d’herència múltiple en la qual només s’hereta la part d’interfície.
Quan creeu una classe, en lloc d’escriure membres de dades completament nous i funcions de membre, el programador pot designar que la nova classe hereti els membres d’una classe existent. Aquesta classe existent s’anomena classe base o superclasse, i la nova classe es coneix com a classe o subclasse derivada.
Ruby també suporta el concepte de subclassificació, és a dir, l’herència i l’exemple següent expliquen el concepte. La sintaxi per ampliar una classe és senzilla. Simplement afegiu un caràcter <
i el nom de la superclasse a la vostra declaració de classe. Per exemple, a continuació definiu una classe BigBox
com a subclasse de Box
.
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# add a new instance method
def printArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area
box.printArea()
Output
Big box area is : 200
12. Methods Overriding
Tot i que podeu afegir noves funcionalitats en una classe derivada, però de vegades voleu canviar el comportament del mètode ja definit en una classe pare. Podeu fer-ho simplement mantenint el nom del mètode igual i substituint la funcionalitat del mètode com es mostra a continuació a l’exemple:
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# define a subclass
class BigBox < Box
# change existing getArea method as follows
def getArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# create an object
box = BigBox.new(10, 20)
# print the area using overriden method.
box.getArea()
13. Operator Overloading
Voldríem que l’operador + realitzés l’addició de dos objectes Box amb l’operador *, per multiplicar l’amplada i l’altura d’una caixa per un escalar, i l’operador unà que negi l’amplada i l’altura de la caixa. Aquí hi ha una versió de la classe Box amb operadors matemàtics definits -
class Box
def initialize(w,h) # Initialize the width and height
@width,@height = w, h
end
def +(other) # Define + to do vector addition
Box.new(@width + other.width, @height + other.height)
end
def -@ # Define unary minus to negate width and height
Box.new(-@width, -@height)
end
def *(scalar) # To perform scalar multiplication
Box.new(@width*scalar, @height*scalar)
end
end
14. Freezing Objects
De vegades, volem evitar que un objecte canviï. El mètode de congelació en Object ens permet fer això, convertint efectivament un objecte en una constant. Es pot congelar qualsevol objecte invocant Object.freeze
. Un objecte congelat pot no ser modificat: no es poden canviar les variables d’instància.
Podeu comprovar si un objecte donat ja està congelat o no utilitza Object.frozen
? mètode, que torna cert en cas que l’objecte estigui congelat si no s’atribueix un valor fals. El següent exemple neteja el concepte -
#!/usr/bin/ruby -w
# define a class
class Box
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# accessor methods
def getWidth
@width
end
def getHeight
@height
end
# setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# create an object
box = Box.new(10, 20)
# let us freez this object
box.freeze
if( box.frozen? )
puts "Box object is frozen object"
else
puts "Box object is normal object"
end
# now try using setter methods
box.setWidth = 30
box.setHeight = 50
# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
Output
Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
from test.rb:39
15. Class Constants
Podeu definir una constant dins d’una classe assignant un valor numèric o de cadena directe a una variable, que es defineix sense utilitzar ni @
ni @@
. Per convenció, mantenim noms constants en majúscules.
Una vegada que es defineix una constant, no es pot canviar el seu valor, però es pot accedir a una constant directament dins d’una classe com una variable, però si voleu accedir a una constant fora de la classe, haureu d’utilitzar nom de classename::constant
tal com es mostra a l’exemple següent.
#!/usr/bin/ruby -w
# define a class
class Box
BOX_COMPANY = "TATA Inc"
BOXWEIGHT = 10
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object
box = Box.new(10, 20)
# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"
Output
Area of the box is : 200
TATA Inc
Box weight is: 10
15. Create Object Using Allocate
Hi pot haver una situació quan vulgueu crear un objecte sense cridar al seu constructor inicialitzant-se, és a dir, utilitzant un mètode nou, en aquest cas podeu trucar a allocate, que crearà un objecte no inicialitzat per a vosaltres com en el següent exemple:
#!/usr/bin/ruby -w
# define a class
class Box
attr_accessor :width, :height
# constructor method
def initialize(w,h)
@width, @height = w, h
end
# instance method
def getArea
@width * @height
end
end
# create an object using new
box1 = Box.new(10, 20)
# create another object using allocate
box2 = Box.allocate
# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"
# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"
Output
Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in `getArea': undefined method `*'
for nil:NilClass (NoMethodError) from test.rb:29
16. Class Information
Si les definicions de classes són codi executable, això implica que s’executen en el context d’un objecte: el jo ha de fer referència a alguna cosa. Descobrirem què és.
#!/usr/bin/ruby -w
class Box
# print class information
puts "Type of self = #{self.type}"
puts "Name of self = #{self.name}"
end
Output
Type of self = Class
Name of self = Box
Això significa que una definició de classe s’executa amb aquesta classe com a objecte actual. Això vol dir que els mètodes de la metaclasia i les seves superclasses estaran disponibles durant l’execució de la definició del mètode.