Septiembre 29, 2004
Un ejemplo del patr�n abstract factory
El patr�n Abstract Factory es uno de los patrones de construcci�n. B�sicamente, proporciona una interfaz que permite crear familias de objetos relacionados entre s�, sin especificar ( ni por lo tanto, conocer a priori ) sus clases concretas.
Voy a intentar explicarlo con un ejemplo un poco m�s �real�. Supongamos que quiero decorar mi casa. Puedo elegir entre dos l�neas de decoraci�n distintas ( en este caso, �Moderna�, o �Cl�sica� ). En principio s�lo voy a comprar las puertas y una televisi�n.
�Por qu� implementar una factor�a abstracta para resolver el problema?. Voy a intentar explicarlo sobre la marcha. En primer lugar voy a suponer que en mi ciudad hay dos tiendas de decoraci�n, la que vende elementos decorativos cl�sicos, y la que vende elementos decorativos modernos. Adem�s, supondr� que las dos tiendas venden los mismos elementos decorativos ( televisores y puertas ).
Bien, si yo quiero comprar una televisi�n, independientemente de lo moderna o cl�sica que sea, voy a la tienda y digo �quiero una televisi�n�. Adem�s, una televisi�n, sea moderna o cl�sica, me permite hacer las mismas cosas: encenderla, apagarla, subir y bajar el volumen, aunque no se haga de la misma forma ( en la moderna, lo hago con el mando a distancia, en la antig�a me tengo que levantar ).
Por lo tanto, ya s� que tengo que ir a la tienda, y pedir una televisi�n. Pero tambi�n puedo encargarle a un transportista que me traiga una televisi�n moderna. Yo no tengo que decirle nada m�s que eso, porque es el transportista es el que se encarga de pensar �vale, me ha dicho que quiere una tele moderna, por tanto, tengo que ir a la tienda donde venden las teles modernas, y pedir una tele�. Pues el transportista es la factor�a abstracta. Yo, como cliente, le pido una televisi�n moderna, y s� que voy a obtener una televisi�n de plasma de 42� que puedo manejar con el mando a distancia adjunto. �Qu� c�mo la ha conseguido el transportista?: no me importa. S�lo me importa que me la traiga.
Antes de empezar a implementarlo en actionScript, una consideraci�n te�rica importante. ActionScript no implementa clases abstractas. Es cierto que se pueden simular, pero no est�n implementadas, por lo que yo no voy a basar la arquitectura de este patr�n en una clase abstracta, sino en un interfaz.
Empecemos. Hemos dicho que tanto si voy yo en persona a la tienda, como si hablo con un transportista, lo �nico que tengo que hacer es decir "quiero una tele". Por lo tanto, tanto las tiendas como el transportista van a implementar un interfaz com�n ( si fu�ramos estrictos, deber�an heredar de una misma clase abstracta que implementara ese interfaz ).
El interfaz ser�:
import net.designnation.patterns.AbstractFactory.* interface net.designnation.patterns.AbstractFactory.IFactoryActions { public function getTV( ): ITVActions; public function getDoor( ): IDoorActions; }
Como puede verse, hay dos acciones posibles: getTV, y getDoor ( es decir, tr�eme una tele, y tr�eme una puerta ).
Por tanto, las dos tiendas ser�n algo as�:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ModernShop implements IFactoryActions { function ModernShop( ) { trace( "He elegido la tienda moderna" ); } public function getTV( ): ITVActions { return new BrandNewTV( ); } public function getDoor( ): IDoorActions { return new ModernDoor( ); } }
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ClassicShop implements IFactoryActions { public function ClassicShop( ) { trace( "He elegido la tienda cl�sica" ); } public function getTV( ): ITVActions { return new OldTV( ); } public function getDoor( ): IDoorActions { return new ClassicDoor( ); } }
Como puede verse, las dos tiendas implementan el interfaz IFactoryActions ( implementan dos m�todos llamados getTV y getDoor, que devolver�n respectivamente, una televisi�n y una puerta ).
Atenci�n. Vamos a ver con m�s atenci�n el m�todo getTV( ).
public function getTV( ): ITVActions { return new OldTV( ); }
�Instanciamos una clase OldTV pero el m�todo devuelve un interfaz?. Cierto. Eso es lo que nos permite tratar a todas las televisiones por igual, sean modernas, antig�as, o de gas. Porque lo que a nosotros nos interesa es poderle decir a la televisi�n: �enci�ndete�, y que �sta lo haga, como sea, pero que lo haga. Eso lo logramos haciendo que las dos clases que representan televisores implementen una interfaz com�n:
interface net.designnation.patterns.AbstractFactory.ITVActions { public function pumpUpTheVolume( ); public function shutUp( ); }
Y por tanto, la televisi�n moderna ser�:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.BrandNewTV implements ITVActions { function BrandNewTV( ) { trace( "He recibido mi televisi�n de plasma de 42 pulgadas" ); } public function pumpUpTheVolume( ) { trace( "por supuesto, espera que busco el mando" ); } public function shutUp( ) { trace( "Presionando esta tecla, el sonido se silencia" ); } }
Mientras que la cl�sica es:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.OldTV implements ITVActions { function OldTV( ) { trace( "Me he comprado una tv vieja" ); } public function pumpUpTheVolume( ) { trace( "Como no tiene mando a distancia, me tengo que levantar a subir el volumen" ); } public function shutUp( ) { trace( "Como no tiene mando a distancia...." ); } }
Lo mismo pasar�a con las puertas. Sea moderna o antigua, la puerta tiene dos posibles acciones, se puede abrir, y se puede cerrar, por lo tanto las dos clases que representan a puertas implementan un interfaz com�n:
interface net.designnation.patterns.AbstractFactory.IDoorActions { public function open( ); public function close( ); }
La puerta moderna:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ModernDoor implements IDoorActions { function ModernDoor( ) { trace( "Constructor de la puerta moderna" ); } public function open( ) { trace( "Abriendo la puerta moderna" ); } public function close( ) { trace( "Cerrando la puerta moderna" ); } }
Y la cl�sica:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ClassicDoor implements IDoorActions { function ClassicDoor( ) { trace( "ClassicDoor constructor" ); } public function open( ) { trace( "Puerta cl�sica abierta " ); } public function close( ) { trace( "Puerta cl�sica cerrada" ); } }
Recapitulemos. Tenemos dos tiendas. Ambas venden puertas y televisores. La tienda cl�sica vende puertas y televisores cl�sicos, y la tienda moderna vende puertas y televisores modernos.
Bien, pues nuestro transportista ser�a la abstract factory:
import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.AbstractFactory { public static var MODERN : Number = 1; public static var CLASSIC : Number = 2; public static function getFactory( shopType: Number ): IFactoryActions { if ( ( shopType & MODERN ) == MODERN ) { return new ModernShop( ); } if ( ( shopType & CLASSIC ) == CLASSIC ) { return new ClassicShop( ); } } }
Esta clase implementa el mismo interfaz que las dos tiendas. Por tanto, yo le dir�, "oye, quiero una tele moderna", y me olvidar� de todos los detalles del proceso. Al final, tendr� algo a lo que podr� subir y bajar el volumen,�. �C�mo?:
import net.designnation.patterns.AbstractFactory.* var factory: IFactoryActions = AbstractFactory.getFactory( AbstractFactory.MODERN ); var myTV: ITVActions = factory.getTV( ); myTV.pumpUpTheVolume( ); var myDoor: IDoorActions = factory.getDoor( ); myDoor.close( );Escrito por Cesar Tardaguila en: Septiembre 29, 2004 07:08 AM | TrackBack
Hola Cesar,
Solo decirte que, como siempre, un post muy �til y un ejemplo con mucha "miga". Vuestro blog se est� conviertiendo en una gu�a de referencia de patrones de dise�o aplicados a ActionScript de visita obligada.
Gracias por compartirlo y un saludo ;)
Posted by: Carlos Rovira en: Septiembre 29, 2004 09:32 AMMis saludos, Cesar.
Quiero felicitarte por el excelente trabajo que aqui plasmaste.
Adios y te mando gracias desde Bolivia.
Posted by: Oscar Rueda en: Noviembre 17, 2004 09:46 AM