Capítulo 17. Métodos singleton
El comportamiento de una instancia viene determinado por su clase, pero hay veces que sabemos que una determinada instancia debe tener un comportamiento especial. En la mayoría de los lenguajes debemos meternos en la problemática de crear otra clase e instanciarla sólo una vez. En Ruby se puede asignar a cada OBJETO sus propios métodos.
ruby> class SingletonTest
ruby| def size
ruby| print «25\n»
ruby| end
ruby| end
nil
ruby> test1 = SingletonTest.new
#<SingletonTest:0x401c4604>
ruby> test2 = SingletonTest.new
#<SingletonTest:0x401c4514>
ruby> def test2.size
ruby| print «10\n»
ruby| end
nil
ruby> test1.size
25
nil
ruby> test2.size
10
nil
En este ejemplo, test1 y test2 pertenecen a la misma clase, pero a test2 se le ha redefinido el método size y por lo tanto se comportan de forma diferente. Un método que pertenece sólo a un objeto se conoce como método singleton.
Los métodos singleton se utilizan frecuentemente en los elementos de un interfaz gráfico de usuario (GUI1) cuando se deben realizar acciones diferentes cuando se pulsan botones diferentes.
Los métodos singleton no son únicos de Ruby, aparecen también en CLOS, Dylan, etc. Otros lenguajes como por ejemplo Self y NewtonScript, sólo tienen métodos singleton. A estos se les conoce como lenguajes basados en prototipos
Notas
- Graphical User Interface
Capítulo 18. Módulos
Los módulos en Ruby son similares a las clases, excepto en:
- Un módulo no puede tener instancias
- Un módulo no puede tener subclases
- Un módulo se define con module … end
Ciertamente … la clase Module de un módulo es la superclase de la clase Class de una clase. ¿Se pilla esto? ¿No?
Sigamos.
Existen dos usos típicos de los módulos. Uno es agrupar métodos y constantes relacionadas en un repositorio central.
El módulo Math de Ruby hace esta función:
ruby> Math.sqrt(2)
1.414213562
ruby> Math::PI
3.141592654
El operador :: indica al intérprete de Ruby qué módulo debe consultar para obtener el valor de la constante (es concebible, que algún otro módulo a parte de Math interprete PI de otra forma). Si queremos referenciar a los métodos o constantes de un módulo, directamente, sin utilizar ::, podemos incluir ese módulo con include:
ruby> include Math
Object
ruby> sqrt(2)
1.414213562
ruby> PI
3.141592654
El otro uso de los módulos se denomina mixin. Algunos lenguajes OO, incluidos el C++, permiten herencia múltiple, es decir, una clase puede heredar de más de una superclase. Un ejemplo de herencia múltiple en el mundo real es un despertador, se podría pensar que un despertador es una clase de reloj y que también pertenece a la clase de objetos
que podríamos llamar zumbadores.
Ruby, con toda la intención del mundo, no implementa herencia múltiple real, aunque la técnica de los mixins es una buena alternativa. Recuérdese que los módulos no se pueden instanciar ni se pueden crear subclases de ellos; pero si se incluye un módulo en la definición de una clase sus métodos quedan añadidos a ella, es decir se asocian (mixin1) a la clase.
Se puede pensar que los mixins son una forma de pedir qué propiedades concretas se desean. Por ejemplo, si una clase tiene un método each funcional, asociarla con el módulo Enumerable de la biblioteca estándar nos proporciona gratuitamente los métodos sort y find.
Esta utilización de los módulos proporciona la funcionalidad básica de la herencia múltiple permitiéndonos representar las relaciones de la clase en una simple estructura en árbol que simplifica considerablemente la implementación del lenguaje (Los diseñadores de Java hicieron una elección parecida).