Plantillas y composición
En la sección anterior vimos como el comportamiento constante (parte del frozenspot) se encapsula en el método plantilla y se separa del comportamiento variable (hotspots) que se implementa en los ganchos, en las subclases. Recuerde, que si bien el comportamiento constante se separa del comportamiento variable en métodos diferentes, al instanciar los robots, ambos comportamientos (grupos de métodos) pasan a formar parte de un único objeto (el robot con los métodos de su clase y los que hereda). Esto, unido al hecho de que la herencia simple no puede lidiar bien con la combinación y abstracción de comportamientos ortogonales, resultó en una explosión de clases y en la duplicación de código.
En diseño que muestra la figura profundiza mas la separación de lo que es constante y lo que varía. No solo lo separa en métodos diferentes, sino que también lo encapsula en objetos diferentes.
El primer cambio a observar en este diseño es que un robot ahora tiene tres partes. Un sistema de locomoción, un sistema de armamento, y una fuente de energía. Hay solo una clase de robot (la clase Robot). El constructor de la clase robot recibe tres parámetros, que corresponden a cada una de estas partes. Crear un tipo específico de robot implica decidir cuales de las alternativas se utilizará para cada parte.
Los sistemas de locomoción se implementan en la jerarquía de la clase LocomotionSystem. Se dispone, por ahora, de dos opciones: colchón de aire (Overcraft) y orugas (Caterpillar). Los sistemas de armas y las fuentes de energía se implementan en las jerarquías ArmsSystem y EnergySource respectivamente. Solo combinando esas clases pueden obtenerse los 8 tipos de robots posibles. El siguiente ejemplo crea un robot y lo configura con locomoción por colchón de aire, armamento laser, y fuente de energía solar.
Robot robot = new Robot(new Overcraft(), new LaserSystem(), new SolarWithBattery());Si apareciese un nuevo tipo de locomoción, tracción 4x4 por ejemplo, alcanza con agregar una subclase FourByFourWheels a LocomotionSystems. La nueva clase implementará el método move(Robot : r) como corresponda. Esto es una ventaja sobre el caso visto en la sección anterior (herencia)
Ahora, cuando un robot recibe el mensaje step(), sigue utilizando su método plantilla (que garantiza el cumplimiento de los pasos canónicos como lo marca la especificación del framework). Sin embargo el método plantilla ya no envía mensajes al objeto mismo (como lo hacía en el caso de herencia) sino que delega las operaciones en sus partes. Entonces, la plantilla está en el robot, y los ganchos en las partes.
Habrá notado que cuando el robot delega las operaciones gancho en sus partes, se pasa el mismo como parámetro. Esto es necesario porque las partes ya no tienen acceso a las variables de instancia del robot ni de las otras partes. En consecuencia al implementar los métodos ganchos (en las partes) solo se puede utilizar los métodos que el robot haga públicos. Esto resulta en un escenario mas restrictivo que el que utilizaba herencia.
Una punto a favor de la implementación por composición es que ahora podemos cambiar el comportamiento del robot en tiempo de ejecución. Alcanza con cambiar la parte afectada por aquella que provee el comportamiento deseado.
Obra publicada con Licencia Creative Commons Reconocimiento Compartir igual 4.0