Para muchos programadores ha sido complicado aprender a programar con objetos debido a la gran cantidad de conceptos que se introducen simultaneamente, pero a mi parecer es porque simplemente la teoría está explicada con una mala metáfora.
Se suele decir que las clases (la forma de definir objetos) son recetas, o son un esqueleto, y es mucho más fácil explicar que son los objetos y para que sirven sin entendemos a las clases como el molde, por ejemplo un molde de una pieza de lego y a los objetos como productos de este molde, o sea los legos.
Requisito (Entender funciones, paso de parámetros, return)
Los objetos tienen un identificador (por ejemplo nº serie), propiedades como el color y tamaño; y comportamientos como acoplarse y causar dolor infinito si uno los pisa.
El como se definen las clases y objetos depende del lenguaje de programación, en ruby que es un lenguaje que a mi me fascina por su simpleza se definen así:
class MoldeLego end
Para crear un objeto a partir de ese molde hay que instanciarlo (otra palabra famosa dentro del mundo orientado a objetos), para instanciar basta con utilizar el nombre de la clase con el método new, o sea:
lego1 = MoldeLego.new
Este lego tiene un identificador, que se puede capturar en ruby con lego1.object_id pero todavía no tiene comportamiento ni propiedades, ahora el secreto para entender bien esta parte es que tanto el molde (la clase) como el objeto pueden tener comportamientos. Cuando los comportamientos son del molde se llaman métodos de clase, cuando lo son del objeto se llaman métodos de instancia.
Para agregar un método de instancia, (o sea un comportamiento del lego) lo hacemos de la siguiente forma:
class MoldeLego def metodoDeInstancia() end end
Por ejemplo algo común sería que el lego tuviera la capacidad de acoplarse con otro lego, para eso el método tendría que ser capaz de recibir como parámetro el otro lego y devolver ahora un nuevo lego más grande.
class MoldeLego def acoplar(otro_lego) return MoldeLego.new()
end end
El problema es que para guardar cualquier estado del lego necesitamosvariables de instancias, y para eso necesitamos definirlas en elconstructor que en el caso de ruby se llama initialize() y si, este método también es un método de instancia, pero además tiene la gracia que se llama sólo cuando se instancia un objeto a través de new.
class MoldeLego def initialize() @size = 1 # las variables de instancia se definen con una @ end end
Cada vez que creamos un lego este tendrá tamaño 1,
lego1 = MoldeLego.new # Este Lego ahora tiene tamaño 1
Hagamos ahora un pequeño resumen:
Los objetos son instancias de una clase, cuando se utilizar la expresión clase.new entonces es cuando se instancia el objeto y automáticamente se llama al constructor, todo lo definido dentro del constructor se ejecuta.
Los constructores sirven principalmente para darle valores iniciales a las variables de instancias.
Volviendo a nuestro ejemplo, si queremos rescatar el tamaño tenemos un problema, no se puede acceder directamente a los estados internos de un objeto debido al principio de encapsulamiento, para acceder a los estados tenemos que crear getters y setters, o sea métodos para obtener los estados (getters) y métodos para cambiarlos (setters), así que nuestro MoldeLego quedaría así:
class MoldeLego def initialize() @size = 1 # las variables de instancia se definen con una @ end def getSize() return @size end def setSize(new_size) @size = new_size end end
Para usarlo, lo haríamos de la siguiente forma:
lego1 = MoldeLego.new # Este Lego ahora tiene tamaño 1 lego1.setSize(5) lego1.getSize()
Exista una mejor forma de definir los getters y setters, que es hacerlo de tal manera que pareciera que estamos trabajando directamente sobre el atributo.
class MoldeLego def initialize() @size = 1 # las variables de instancia se definen con una @ end def size() return @size end def size=(new_size) @size = new_size end end
de esta forma podemos ocupar el objeto así:
lego1 = MoldeLego.new # Este Lego ahora tiene tamaño 1 lego1.size # devuelve 1, pues es el tamaño original lego1.size = 5 lego1.size # devuelve 5, ya que lo cambiamos
ahora en ruby es posible definir de forma simultánea la variable, los getters y setters a través del attr_accessor:
class MoldeLego attr_accessor :size
def initialize() @size = 1 # las variables de instancia se definen con una @ end end
y para ocuparlo sería exactamente que la forma anterior, ahora volvamos a la idea de acoplar:
class MoldeLego attr_accessor:size
# Pasamos un valor al constructor # para poder crear legos de otros tamaños # en caso de que se omita es de tamaño 1 def iniatilize(size_orig = 1) @size = size_orig end
def acoplar(otro_lego) return MoldeLego.new(self.size + otro_lego.size) # devolvemos un lego de la suma del tamaño de los otros legos end
end
lego1 = MoldeLego.new lego2 = MoldeLego.new lego3 = lego1.acoplar(otro_lego)
Todavía podemos hacer una mejor más, en ruby al igual que otros lenguajes se puede redefinir una operación, en este caso vamos a redefinir la suma (sólo para los legos):
class MoldeLego attr_accessor:size
# Pasamos un valor al constructor # para poder crear legos de otros tamaños # en caso de que se omita es de tamaño 1 def iniatilize(size_orig = 1) @size = size_orig end
def +(otro_lego) return MoldeLego.new(self.size + otro_lego.size) # devolvemos un lego de la suma del tamaño de los otros legos end
end
Gracias a eso ahora podemos simplemente escribir:
lego1 = MoldeLego.new lego2 = MoldeLego.new lego3 = lego1 + lego2
¿Que pasaría si quisiéramos contar cuantos legos se han creado?
Eso no lo podemos hacer con una variable de instancia, necesitamos que sea el molde cuente, (algo así como imprimir el número de serie en el producto), o sea es una propiedad de la clase, estas se llaman formalmente variables de clase, en ruby se crean con 2 @@:
class MoldeLego attr_accessor:size @@cuenta_legos = 0 end
A diferencia de la variables de instancias estas no requieren definirse en el constructor, pues existen para la clase, independiente de si existen legos o no.
ahora si quisiéramos contar cada vez que se crea un lego nuevo, podríamos hacerlo así:
class MoldeLego attr_accessor:size @@cuenta_legos = 0 def iniatilize(size_orig = 1) @size = size_orig @@cuenta_legos += 1 end end
si quisiéramos obtener las variables de clase toparíamos con el mismo problema de encapuslamiento, tenemos que definir getters y setters para estas, ahora lamenteblemente la sintaxis en ruby no es tan bonita, se hace asi:
class MoldeLego class << self; attr_accessor :cuenta_legos end attr_accessor:size @@cuenta_legos = 0 def iniatilize(size_orig = 1) @size = size_orig @@cuenta_legos += 1 end end
Sólo una cosa está quedando en el tintero, ¿cómo crear métodos de clase más allá de los getters y setter?
Para eso vamos a ocupar self, para este ejemplo voy a definir un getter de la forma no tan bonita para la cuenta legos, sería así:
class MoldeLego class << self; attr_accessor :cuenta_legos end def self.getCuentaLegos() return @@cuenta_legos end end
De los legos al molde:
Una de las curiosidades que tienen los lenguajes orientados a objetos es que desde las instancias podemos rescatar las propiedades de la clase, pero desde las clase no podemos saber cuales son las propiedades de las instancias.
En la metáfora del lego podemos saber incluso de que color era el molde que lo fabricó sin embargo desde el molde no podemos saber de que color o cuantos legos se han acoplado a menos que llevemos específicamente la cuenta como en el caso del número de serie.
Para rescatar la clase a partir de la instancia basta con hacer:
lego.class.cuentaLegos
lo que es exactamente lo mismo que:
MoldeLego.cuentaLegos
Es importante no confundir esta metafora con la herencia, esta última es una característica de los objetos que les permite obtener los métodos y propiedades de sus padres, pero este tema lo tocaremos en un próximo artículo.
Con lo vista ya entendemos lo básico de objetos en Ruby (es bueno saber que con excepción de los attr_accessor este tutorial aplica a otros lenguajes orientados a objetos)
- 412441881723586638 - August 13, 2024
- 319015961723586638 - August 13, 2024
- 406846251723568762 - August 13, 2024
- 660616821723568764 - August 13, 2024
- Ricky Casino Review ️ Claim A$7500 And Up 550 Fs Bonu - July 8, 2024
- ️ 1win Casino And Apuestas Deportivas ⭐️ Página Oficial 1wi - July 6, 2024
- Мостбет%3A Зеркало%2C Вход%2C Казино%2C Официальный Сайт%2C Играт - June 11, 2024
“Companhia De Trens Urbanos De Porto Alegre S A - June 4, 2024Mostbet Login To Your Web Casino Personal Account In Bangladesh! - June 3, 2024- Mostbet Türkiye Çevrimiçi Kumarhane Mostbet Casin - May 20, 2024
Leave a Reply