Ruby Orientado a objetos

Ruby es un lenguaje puramente orientado a objetos; todo en Ruby se presenta en forma de objetos. Cada valor en Ruby es un objeto, incluso las cosas más primitivas: cadenas, números, e incluso true y false son objetos. La clase en sí misma también es unobjeto, que esClassuna instancia de la clase. Este capítulo le explicará todas las características principales relacionadas con la orientación a objetos de Ruby.

Las clases se utilizan para especificar la forma de los objetos; combinan representación de datos y métodos, organizando los datos en un paquete ordenado. Los datos y métodos dentro de una clase se denominan miembros de la clase.

Definición de clases en Ruby

Cuando define una clase, en realidad está definiendo el plano de un tipo de datos. Esto no define ningún dato en sí, sino que define qué significa el nombre de la clase, es decir, de qué estará compuesto el objeto de la clase y qué operaciones se pueden realizar sobre dicho objeto.

La definición de una clase comienza con la palabra claveclass, seguida delnombre de la clase, y finalmente termina con unendpara indicar la finalización de la definición de la clase. Por ejemplo, usamos la palabra clave class para definir la clase Box, como se muestra a continuación:

class Box code end

Según la convención, el nombre debe comenzar con una letra mayúscula. Si contiene varias palabras, cada palabra debe comenzar con mayúscula, pero sin separadores entre ellas (por ejemplo: CamelCase).

Definición de objetos Ruby

Las clases proporcionan el plano de los objetos, por lo que básicamente los objetos se crean a partir de las clases. Usamos lanewpalabra clave para declarar objetos de la clase. La siguiente declaración declara dos objetos de la clase Box:

box1 = Box.new box2 = Box.new

El método initialize

initializees un método de clase estándar de Ruby, es el constructor de la clase, similar alconstructorconstructor en otros lenguajes de programación orientada a objetos. Cuando se desea inicializar algunas variables de clase al crear el objeto, el método initialize resulta útil. Este método acepta una serie de parámetros y, al igual que otros métodos de Ruby, al usarlo debe colocarse delantedefla palabra clave, como se muestra a continuación:

class Box def initialize(w,h) @width, @height = w, h end end

Variables de instancia

Las variables de instanciason atributos de la clase; cuando se crea un objeto con la clase, se convierten en atributos del objeto. Los atributos de cada objeto se asignan por separado y no se comparten valores con otros objetos. Dentro de la clase, estos atributos se acceden mediante el operador @; fuera de la clase, se accede mediante los llamadosmétodos de accesodepúblicospara acceder. A continuación, la clase definida anteriormenteBoxA continuación, la clase definida anteriormente

class Box def initialize(w,h) #como ejemplo, usaremos @width y @height como variables de instancia de la clase Box. @width, @height = w, h end end

Métodos de acceso (getter) y establecedores (setter)

Métodos de acceso (getter) y establecedores (setter)

Ejemplo

#!/usr/bin/ruby -w #Ejemplo class Box #Definir la clase def initialize(w,h) @width, @height = w, h end #Constructor def printWidth @width end def printHeight @height end end #Métodos de acceso box = Box.new(10, 20) #Crear el objeto e inicializar la altura y el ancho de la caja x = box.printWidth() y = box.printHeight() puts "Usar los métodos de acceso" puts "Ancho de la caja : #{x}"

Alto de la caja : #{y}

Pruébalo »

盒子宽度 : 10
盒子高度 : 20

Cuando se ejecuta el código anterior, produce el siguiente resultado:De manera similar a los métodos de acceso que se usan para acceder al valor de las variables, Ruby proporciona una forma de pasar parámetros desde fuera de la clase a las variables ya definidas en la clase, es decir, los llamadosmétodos establecedores (setter)

Ejemplo

#!/usr/bin/ruby -w #Ejemplo class Box #Definir la clase def initialize(w,h) @width, @height = w, h end #Método constructor def getWidth @width end def getHeight @height end #Métodos de acceso def setWidth=(value) @width = value end def setHeight=(value) @height = value end end #Métodos establecedores (setter) box = Box.new(10, 20) #Crear el objeto box.setWidth = 30 box.setHeight = 50 #Usar los métodos establecedores (setter) x = box.getWidth() y = box.getHeight() puts "Usar los métodos de acceso" puts "Ancho de la caja : #{x}"

Alto de la caja : #{y}

Pruébalo »

盒子宽度 : 30
盒子高度 : 50

Cuando se ejecuta el código anterior, produce el siguiente resultado:attr_accessor :variable_name、attr_reader :variable_name、attr_writer :variable_nameDebido a que ambos métodos son muy comunes, Ruby defineaccessor=reader+writer。

tres métodos para declarar atributos. Entre ellos::Tenga también en cuenta: el nombre de la variable debe ir precedido de,@, y entre los nombres de las variables se debe usar

Métodos de instancia

Métodos de instanciaLos métodos de instanciadefse definen igual que los demás métodos, utilizando la

Ejemplo

#!/usr/bin/ruby -w #Ejemplo class Box #Definir la clase def initialize(w,h) @width, @height = w, h end #Método constructor def getArea @width * @height end end #Método de instancia box = Box.new(10, 20) #Crear el objeto a = box.getArea() puts "Area of the box is : #{a}"

Llamar al método de instancia

Pruébalo »

Area of the box is : 200

Métodos de clase y variables de clase

Métodos de clase y variables de claseLas variables de clase

son variables compartidas por todas las instancias de la clase. En otras palabras, una variable de clase puede ser accedida por todas las instancias de objetos. Las variables de clase llevan como prefijo dos caracteres @ (@@) y deben inicializarse en la definición de la clase, como se muestra en el siguiente ejemplo.Los métodos de clasedef self.methodname()se definen usandoclassname.methodnamedef, y terminan con el delimitador end. Los métodos de clase se pueden invocar usando la forma

Ejemplo

#!/usr/bin/ruby -w class Box #Ejemplo @@count = 0 def initialize(w,h) #Inicializar variables de clase @width, @height = w, h @@count += 1 end def self.printCount() puts "Box count is : #@@count" end end #Asignar valores a las variables de instancia box1 = Box.new(10, 20) box2 = Box.new(30, 100) #Crear dos objetos Box.printCount()

Llamar al método de clase para mostrar el contador de cajas

Pruébalo »

Box count is : 2

El método to_s

El método to_sto_sCualquier clase que defina tiene un

Ejemplo

#!/usr/bin/ruby -w class Box #Ejemplo def initialize(w,h) @width, @height = w, h end #Método constructor def to_s "(w:#@width,h:#@height)" #Definir el método to_s end end #Formato de cadena del objeto box = Box.new(10, 20) #Crear el objeto puts "String representation of box is : #{box}"

Llamar automáticamente al método to_s

Pruébalo »

String representation of box is : (w:10,h:20)

Control de acceso

Control de accesoRuby le ofrece tres niveles de protección para los métodos de instancia, que sonpublic, private o protected

  • . Ruby no aplica ningún control de acceso a las variables de instancia ni de clase.Métodos public:
  • Los métodos public pueden ser llamados por cualquier objeto. Por defecto, todos los métodos son public, excepto el método initialize, que siempre es private.Métodos private:
  • Los métodos private no pueden accederse ni verse desde fuera de la clase. Solo los métodos de la clase pueden acceder a los miembros privados.Métodos protected:

Los métodos protected solo pueden ser invocados por objetos de la clase y sus subclases. El acceso también solo puede realizarse dentro de la clase y sus subclases.

Ejemplo

#!/usr/bin/ruby -w #Ejemplo class Box #Definir la clase def initialize(w,h) @width, @height = w, h end #Método constructor def getArea getWidth() * getHeight end #Los métodos de instancia son public por defecto def getWidth @width end def getHeight @height end # make them private private :getWidth, :getHeight #Definir métodos de acceso private def printArea @area = getWidth() * getHeight puts "Big box area is : #@area" end #Método de instancia para mostrar el área protected :printArea end #Hacer que el método de instancia sea protected box = Box.new(10, 20) #Crear el objeto a = box.getArea() puts "Area of the box is : #{a}" #Llamar al método de instancia box.printArea()

Intentar llamar al método de instancia protected

Pruébalo »

Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height=20, @width=10> (NoMethodError)

Herencia de clases

La herencia es uno de los conceptos más importantes en la programación orientada a objetos. La herencia nos permite definir una clase basándonos en otra clase, lo que facilita la creación y el mantenimiento de aplicaciones.

La herencia ayuda a reutilizar código y a ejecutar rápidamente. Desafortunadamente, Ruby no admite la herencia múltiple, pero Ruby admitemixinsmixins. Los mixins son como una implementación específica de la herencia múltiple, en la que solo la parte de la interfaz es heredable.

Al crear una clase, el programador puede especificar directamente que la nueva clase herede los miembros de una clase existente, evitando así tener que escribir nuevos miembros de datos y funciones miembro desde cero. Esta clase existente se denominaclase base o clase padre, y la nueva clase se denominaclase derivada o subclase。

Ruby también proporciona el concepto de subclasificación, que es la herencia. El siguiente ejemplo explica este concepto. La sintaxis para extender una clase es muy sencilla. Solo hay que añadir un carácter < y el nombre de la clase padre a la declaración de la clase. Por ejemplo, a continuación se define la claseBigBoxSíBoxsubclase de:

Ejemplo

#!/usr/bin/ruby -w #Definir la clase class Box #Método constructor def initialize(w,h) @width, @height = w, h end #Método de instancia def getArea @width * @height end end #Definir la subclase class BigBox < Box #Añadir un nuevo método de instancia def printArea @area = @width * @height puts "Big box area is : #@area" end end #Crear el objeto box = BigBox.new(10, 20) #Mostrar el área box.printArea()

Pruébalo »

Cuando se ejecuta el código anterior, produce el siguiente resultado:

Big box area is : 200

Sobrecarga de métodos

Aunque puede añadir nuevas funcionalidades en la clase derivada, a veces es posible que desee cambiar el comportamiento de un método ya definido en la clase padre. En este caso, puede mantener el nombre del método sin cambios y sobrescribir la funcionalidad del método, como se muestra en el siguiente ejemplo:

Ejemplo

#!/usr/bin/ruby -w #Definir la clase class Box #Método constructor def initialize(w,h) @width, @height = w, h end #Método de instancia def getArea @width * @height end end #Definir la subclase class BigBox < Box #Cambiar el método getArea existente def getArea @area = @width * @height puts "Big box area is : #@area" end end #Crear el objeto box = BigBox.new(10, 20) #Mostrar el área usando el método sobrescrito box.getArea()

Pruébalo »

El resultado de ejecutar el ejemplo anterior es:

Big box area is : 200

Sobrecarga de operadores

Queremos usar el operador + para realizar la suma vectorial de dos objetos Box, usar el operador * para multiplicar el ancho y la altura de Box, y usar el operador unario - para negar el ancho y la altura de Box. A continuación se muestra una versión de la clase Box con definiciones de operadores matemáticos:

class Box def initialize(w,h) #Inicializar width y height @width,@height = w, h end def +(other) #Definir + para realizar la suma vectorial Box.new(@width + other.width, @height + other.height) end def -@ #Definir el operador unario - para negar width y height Box.new(-@width, -@height) end def *(scalar) #Realizar la multiplicación escalar Box.new(@width*scalar, @height*scalar) end end

Congelar objetos

A veces, queremos evitar que un objeto sea modificado. En Object, el método freeze puede lograr esto, convirtiendo efectivamente un objeto en una constante. Cualquier objeto puede ser congelado llamando aObject.freezepara congelarlo. Un objeto congelado no puede ser modificado, es decir, no se pueden cambiar sus variables de instancia.

Puede usar elObject.frozen?método para comprobar si un objeto dado ya está congelado. Si el objeto está congelado, el método devuelve true; de lo contrario, devuelve false. El siguiente ejemplo explica este concepto:

Ejemplo

#!/usr/bin/ruby -w #Definir la clase class Box #Método constructor def initialize(w,h) @width, @height = w, h end #Método de acceso def getWidth @width end def getHeight @height end #Método setter def setWidth=(value) @width = value end def setHeight=(value) @height = value end end #Crear el objeto box = Box.new(10, 20) #Vamos a congelar el objeto box.freeze if( box.frozen? ) puts "Box object is frozen object" else puts "Box object is normal object" end #Ahora intentemos usar el método setter box.setWidth = 30 box.setHeight = 50 #Usar el método de acceso x = box.getWidth() y = box.getHeight() puts "Width of the box is : #{x}" puts "Height of the box is : #{y}"

Pruébalo »

Cuando se ejecuta el código anterior, produce el siguiente resultado:

Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
        from test.rb:39

Constantes de clase

Puede definir una constante dentro de la clase asignando un valor numérico o de cadena directo a una variable. La definición de una constante no requiere el uso de @ o @@. Por convención, los nombres de las constantes se escriben en mayúsculas.

Una vez que una constante está definida, no puede cambiar su valor. Puede acceder a la constante directamente dentro de la clase, como si fuera una variable, pero si desea acceder a la constante desde fuera de la clase, debe usarclassname::constant, como se muestra en el siguiente ejemplo.

Ejemplo

#!/usr/bin/ruby -w #Definir la clase class Box BOX_COMPANY = "TATA Inc" BOXWEIGHT = 10 #Método constructor def initialize(w,h) @width, @height = w, h end #Método de instancia def getArea @width * @height end end #Crear el objeto box = Box.new(10, 20) #Llamar al método de instancia a = box.getArea() puts "Area of the box is : #{a}" puts Box::BOX_COMPANY puts "Box weight is: #{Box::BOXWEIGHT}"

Pruébalo »

Cuando se ejecuta el código anterior, produce el siguiente resultado:

Area of the box is : 200
TATA Inc
Box weight is: 10

Las constantes de clase pueden ser heredadas y también pueden sobrescribirse como los métodos de instancia.

Crear objetos con allocate

Puede haber una situación en la que desee crear un objeto sin llamar al constructor del objeto,initializees decir, sin usar el método new para crear un objeto. En este caso, puede llamar a allocate para crear un objeto no inicializado, como se muestra en el siguiente ejemplo:

Ejemplo

#!/usr/bin/ruby -w #Definir la clase class Box attr_accessor :width, :height #Método constructor def initialize(w,h) @width, @height = w, h end #Método de instancia def getArea @width * @height end end #Crear el objeto con new box1 = Box.new(10, 20) #Crear otro objeto con allocate box2 = Box.allocate #Llamar al método de instancia con box1 a = box1.getArea() puts "Area of the box is : #{a}" #Llamar al método de instancia con box2 a = box2.getArea() puts "Area of the box is : #{a}"

Pruébalo »

Cuando se ejecuta el código anterior, produce el siguiente resultado:

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

Información de la clase

El self de Ruby tiene similitudes con el this de Java, pero también es muy diferente. En Java, los métodos se referencian dentro de métodos de instancia, por lo que this normalmente apunta al objeto actual. En Ruby, el código se ejecuta línea por línea, por lo que en diferentes contextos, self tiene diferentes significados. Veamos el siguiente ejemplo:

Ejemplo

#!/usr/bin/ruby -w class Box #Mostrar información de la clase puts "Class of self = #{self.class}" puts "Name of self = #{self.name}" end

Pruébalo »

Cuando se ejecuta el código anterior, produce el siguiente resultado:

Class of self = Class
Name of self = Box

Esto significa que la definición de la clase se puede ejecutar teniendo la clase como objeto actual, y también significa que ese método en la metaclase y la clase padre está disponible durante la ejecución de la definición del método.

Otras extensiones