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.