Factory Method (patrón de diseño)En diseño de software, el patrón de diseño Factory Method consiste en utilizar una clase
constructora (al estilo del Abstract Factory) abstracta con unos cuantos métodos definidos y otro(s)
abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado. Es una
simplificación del Abstract Factory, en la que la clase abstracta tiene métodos concretos que usan
algunos de los abstractos; según usemos una u otra hija de esta clase abstracta, tendremos uno u
otro comportamiento.
Estructura[editar · editar código]
Las clases principales en este patrón son el creador y el producto. El creador necesita crear
instancias de productos, pero el tipo concreto de producto no debe ser forzado en las subclases del
creador, porque las posibles subclases del creador deben poder especificar subclases del producto
para utilizar.
La solución para esto es hacer un método abstracto (el método de la fábrica) que se define en el
creador. Este método abstracto se define para que devuelva un producto. Las subclases del creador
pueden sobrescribir este método para devolver subclases apropiadas del producto...
Ejemplo de código (en Java)[editar · editar código]
abstract class Creator{
// Definimos método abstracto
public abstract Product factoryMethod();
}
Ahora definimos el creador concreto.
public class ConcreteCreator extends Creator{
public Product factoryMethod() {
return new ConcreteProduct();
}
}
Y definimos el producto y su implementación concreta.
public interface Product{
public void operacion();
}
public class ConcreteProduct implements Product{
public void operacion(){
System.out.println("Una operación de este producto");
}
}
Y un ejemplo de uso :
public static void main(String args[]){
Creator aCreator;
aCreator = new ConcreteCreator();
Product producto = aCreator.factoryMethod();
producto.operacion();
}
Abstract FactoryAbstract Factory (Fábrica Abstracta) es un patrón de diseño para el desarrollo de software.
Índice
[ocultar]
1 Contexto y problema
2 Aspecto estático
3 Un ejemplo
4 Véase también
5 Enlaces externos
Contexto y problema[editar · editar código]
Contexto: Debemos crear diferentes objetos, todos pertenecientes a la misma familia. Por ejemplo:
las bibliotecas para crear interfaces gráficas suelen utilizar este patrón y cada familia sería un
sistema operativo distinto. Así pues, el usuario declara un Botón, pero de forma más interna lo que
está creando es un BotónWindows o un BotónLinux, por ejemplo.
El problema que intenta solucionar este patrón es el de crear diferentes familias de objetos.
El patrón Abstract Factory está aconsejado cuando se prevé la inclusión de nuevas familias de
productos, pero puede resultar contraproducente cuando se añaden nuevos productos o cambian
los existentes, puesto que afectaría a todas las familias creadas.
Aspecto estático[editar · editar código]
La estructura típica del patrón Abstract Factory es la siguiente:
Cliente: La clase que llamará a la factoría adecuada ya que necesita crear uno de los objetos
que provee la factoría, es decir, Cliente lo que quiere es obtener una instancia de alguno de los
productos (ProductoA, ProductoB).
AbstractFactory: Es la definición de la interfaces de las factorías. Debe de proveer un método
para la obtención de cada objeto que pueda crear. ("crearProductoA()" y "crearProductoB()")
Factorías Concretas: Estas son las diferentes familias de productos. Provee de la instancia
concreta de la que se encarga de crear. De esta forma podemos tener una factoría que cree los
elementos gráficos para Windows y otra que los cree para Linux, pudiendo poner fácilmente
(creando una nueva) otra que los cree para MacOS, por ejemplo.
Producto abstracto: Definición de las interfaces para la familia de productos genéricos. En el
diagrama son "ProductoA" y "ProductoB". En un ejemplo de interfaces gráficas podrían ser
todos los elementos: Botón, Ventana, Cuadro de Texto, Combo... El cliente trabajará
directamente sobre esta interfaz, que será implementada por los diferentes productos
concretos.
Producto concreto: Implementación de los diferentes productos. Podría ser por ejemplo
"BotónWindows" y "BotónLinux". Como ambos implementan "Botón" el cliente no sabrá si está
en Windows o Linux, puesto que trabajará directamente sobre la superclase o interfaz.
Un ejemplo[editar · editar código]
Veremos un ejemplo didáctico y basado en el libro Head First Design Patterns, de O'Reilly.
Supongamos que disponemos de una cadena de pizzerías. Para crear pizzas disponemos de un
método abstracto en la clase Pizzería que será implementada por cada subclase de Pizzería.
abstract Pizza crearPizza()
Concretamente se creará una clase PizzeríaZona por cada zona, por ejemplo la Pizzería de New
York sería PizzeriaNewYork y la de Californía PizzeríaCalifornia que implementarán el método con
los ingredientes de sus zonas.
Las pizzas son diferentes según las zonas. No es igual la pizza de New York que la pizza de
California. Igualmente, aunque usarán los mismos ingredientes (tomate, mozzarella...) no los
obtendrán del mismo lugar, cada zona los comprará donde lo tenga más cerca. Así pues podemos
crear un método creador de Pizza que sea
Pizza(FactoriaIngredientes fi);
Como vemos utilizamos la factoría abstracta (no las concretas de cada zona, como podría ser
IngredientesNewYork o IngredientesCalifornia). Pizza podrá obtener los ingredientes de la factoría
independientemente de donde sea. Sería fácil crear nuevas factorías y añadirlas al sistema para
crear pizzas con estos nuevos ingredientes. Efectivamente, en este ejemplo cliente es Pizza y es
independiente de la Factoría usada.
El creador de la Pizza será el encargado de instanciar la factoría concreta, así pues los encargados
de instanciar las factorías concretas serán las pizzerías locales. En PizzeríaNewYork podemos tener
el método crearPizza() que realice el siguiente trabajo:
Pizza crearPizza() {
FactoríaIngredientes fi = new IngredientesNewYork();
Pizza pizza = new Pizza(fi); // Uso de la factoría
pizza.cortar();
pizza.empaquetar();
return pizza;
}
Como conclusión podemos observar que gracias a la factoría de ingredientes crear una nueva zona,
por ejemplo una pizzería en Barcelona, no nos implicaría estar modificando el código existente, solo
deberemos extenderlo (uno de los pilares de la Ingeniería del software) ya crearíamos la subclase
de Pizzería: PizzeríaBarcelona que al instanciar la factoría solo debería escoger la factoría de
Barcelona. Obviamente se debería crear la factoría de Barcelona que se encargaría de crear los
productos obtenidos de Barcelona. Así que en ningún momento modificamos las pizzerías
existentes, la superclase pizzería o las otras factorías o productos, solo creamos nuevas clases.
Abstract Factory
El patrón Abstract Factory nos permite crear, mediante una interfaz, conjuntos o familias
de objetos (denominados productos) que dependen mutuamuente y todo esto sin
especificar cual es el objeto concreto.
¿Que usos tiene el patrón Abstract Factory?
Este patrón se puede aplicar cuando:
o Un sistema debe ser independiente de como sus objetos son creados.
o Un sistema debe ser 'configurado' con una cierta familia de productos.
o Se necesita reforzar la noción de dependencia mutua entre ciertos objetos.
Estructura del Patrón Abstract Factory
El asterisco (*) representa que la clase/operación es abstracta.
Elementos del Patrón Abstract Factory
FabricaAbstracta*: Define un conjunto de métodos (interfaz) para la creación de
productos abstractos.
o FabricaConcreta1/2: Implementa la interfaz de la FabricaAbstracta para la creación
de los distintos productos concretos.
o ProductoAbstractoA*/B*: Define la interfaz de los objetos de tipo ProductoA/B.
o ProductoConcretoA1/A2/B1/B2: Implementan su respectiva interfaz representando
un producto concreto.
Pros/Contras del Patrón Abstract Factory
o + Brinda flexibilidad al aislar a las clases concretas.
o + Facilita cambiar las familias de productos.
o - Para agregar nuevos productos se deben modificar tanto las fabricas abstractas
como las concretas.
Ejemplo del Patrón Abstract Factory
Teniendo en cuenta la siguiente jerarquía de clases, la cual trata de representar muy por
arriba dos familias de productos (DVD y BluRay) cada uno con un par de variantes (simple
y doble capa) para que permiten mostrar diferentes aspectos a tener en cuenta a la hora
de usar este patrón.
Vemos como sería el producto abstracto:
1. public abstract class Disco implements Prototipo {
2. @Override
3. public abstract Prototipo clone();
4.
5. public abstract String getCapacidad();
6.
7. public abstract String getNombre();
8.
9. public abstract String getPrecio();
10.
11. @Override
12. public String toString() {
13. return getNombre() + " (" + getCapacidad() + ")";
14. }
15. }
El producto DVD extendemos del Disco
1. public abstract class DVD extends Disco {
2. ...
3. }
Y el producto concreto del DVD extenderá de la anterior clase:
1. public class DVD_CapaSimple extends DVD {
2.
3. @Override
4. public Prototipo clone() {
5. return new DVD_CapaSimple();
6. }
7.
8. @Override
9. public String getCapacidad() {
10. return "4.7GB";
11. }
12.
13. @Override
14. public String getNombre() {
15. return "DVD Capa Simple";
16. }
17.
18. @Override
19. public String getPrecio() {
20. return "5.00$";
21. }
22.
23. }
Vamos a construir un AbstractFactory que nos permita crear discos de DVD o BluRay de
simple y doble capa usando el siguiente diseño:
La factoría abstracta la definiríamos mediante un interface:
1. public interface FabricaDiscos {
2.
3. public BluRay crearBluRay();
4. public DVD crearDVD();
5. }
Y sobre ese interface implementamos una de las fábricas concretas, en este caso la de
FabricaDiscos_CapaSimple:
1. public class FabricaDiscos_CapaSimple implements FabricaDiscos {
2.
3. @Override
4. public BluRay crearBluRay() {
5. return new BluRay_CapaSimple();
6. }
7.
8. @Override
9. public DVD crearDVD() {
10. return new DVD_CapaSimple();
11. }
12.
13. }
Veamos como quedaría el código fuente en Java para utilizar el patrón Abstract Factory:
1. FabricaDiscos fabrica;
2. DVD dvd;
3. BluRay bluray;
4.
5. fabrica = new FabricaDiscos_CapaSimple();
6. dvd = fabrica.crearDVD();
7. bluray = fabrica.crearBluRay();
8.
9. System.out.println(dvd);
10. System.out.println(bluray);
11.
12. fabrica = new FabricaDiscos_CapaDoble();
13. dvd = fabrica.crearDVD();
14. bluray = fabrica.crearBluRay();
15.
16. System.out.println(dvd);
17. System.out.println(bluray);
En el código vemos que sobre la fábrica podemos crear objetos de diferentes tipos y que
podríamos ir creciendo en productos atendiendo a nuestras necesidades.
1. fabrica = new FabricaDiscos_CapaSimple();
2. dvd = fabrica.crearDVD();
3. bluray = fabrica.crearBluRay();
Espero que hayáis podido apreciar la flexibilidad que nos brinda el patrón Abstract Factory.
Los patrones de diseño son soluciones que se puede aplicar a problemas
recurrentes en el diseño de software, los mismos cubren aspectos como la creación
e interacción de objetos así como la comunicación entre ellos, ademas estos nos
hacen mas fácil el reutilizar componentes de software basándose en técnicas ya
probadas una y otra vez en distintas aplicaciones pudiendo realizar diseños de una
manera mas rápida y simplificada.
Los patrones de diseño se dividen en tres grupos: creacionales, estructurales, y de
comportamiento, en este primer post empezare hablando del patrón creacional
Abstract Factory.
Definicion de Abstract Factory: este patrón nos provee una interfaz para crear
familias de objetos relacionados o dependientes entre ellos sin especificar una clase
en concreto.
Diagrama UML
Participantes:
AbstractFactory: declara una interfaz para operaciones que crean un producto
abstracto
ConcreteFactory : implementa la operación para crear un producto en concreto
AbstractProduct : declara una interfaz para un tipo de producot en concreto
Product: define un producto que será creado por su ConcreteFactory
correspondiente e implementa la interfaz AbstractProduct
Client: usa la interfaz declarada por el AbstractFactory y AbstractProduct
Entre los problemas mas comunes resueltos por el patrón Abstract Factory se
encuentra:
- La creación de un objeto creando su tipo de manera dinámica de forma que no nos
veamos atados a una implementación sino a una interfaz haciendo mas fácil los
cambios futuros.
- Nos permite jugar con la manera de satisfacer las peticiones hacia
una operación determinada, de esta manera es mas sencillo cambiar la forma en
que se atienden las peticiones desde una operación en concreto.
- Nos permite poder manejarnos entre distintas plataformas de hardware y
software al poder ser capaces de realizar diferentes manejos de
las peticiones basándonos en las plataformas.
También es muy usado en casos donde se requiere crear una librería de clases de
productos ya que solo revelamos sus interfaces mas no su implementación .
Creando objetos con el diseño Abstract Factory. Factory, es un patrón de diseño. En distintas paginas de la web los patrones de diseño son definidos como: “soluciones simples y elegantes a problemas específicos y comunes del diseño orientado a objetos. Son soluciones basadas en la experiencia y que se ha demostrado que funcionan”. Existen distintos patrones, como el command, singleton, etc, pero en este post solo hablaremos de Factory o Fábrica, especificamente con Abstract Factory o Fábrica Abstracta.
Entonces, ¿Qué hace factory?, "este patrón delega en una clase la responsabilidad de creación de objetos de otras clases. Puede evolucionar a un Factory Method o a un Abstract Factory".
Factory Method: "define una interfaz para crear objetos, pero deja que sean las subclases quienes decidan qué clases instanciar; permite que una clase delegue en sus subclases la creación de objetos." Abstract Factory: " El patrón Abstract Factory proporciona una interfaz para crear familias de objetos relacionados o que dependen entre sí, sin especificar sus clases concretas". "Normalmente se implementa usando Factory Method".
Para entender un poco mejor el diseño Abstract Factory, he creado un pequeño ejemplo en java, para este, se me ocurrió plantear lo siguiente: una empresa de Servicios de comunicación cualquiera, puede tener varios productos que ofrecer para permitir que sus usuarios se comuniquen. Se pueden encontrar teléfonos móviles, teléfonos fijos, internet y tal vez otros mas. En el caso de los teléfonos para poder establecer una comunicación se necesitan los códigos de área para el caso de los fijos (más el número telefónico), y los de la compañía para el caso de los móviles, sin embargo para el internet no necesito este tipo de códigos, puesto que en un principio (y para este ejemplo) no realiza llamadas.
Comencé creando una interfaz llamada Servicio, donde únicamente declaro un método, que para este ejemplo es llamado codigoDeServicio, pues de cada servicio ofrecido por la compañía voy a querer saber el distinto tipo de código usado, para llamar.
Cree también otra interfaz de tipo Servicio llamada ServicioDeComunicacion, y declaro en ella un método, para la creación, que se encargaran de implementar cada fabrica.
La idea siguiente sería, crear tres clases: TelefonoMovil, TelefonoFijo e Iternet, que implementaran la interfaz Servicio, como cada clase lo requiera. Para este ejemplo, estas clases solo imprimirán el código que se necesite para realizar una llamada.
Como después voy a querer manejar varios de estos objetos, creo las clases fábricas, que implementaran la interfaz ServicioDeComunicacion:
Termino encapsulando (por decirlo de alguna manera) las tres fábricas anterios, creando una clase FabricaPrincipal que posea un metodo para crear cualquier tipo de fábrica que se pase por parametro, aseguro esto porque el tipo de dato de lo que recibe el metodo, es ServicioDeComunicacion (interfaz que implementa cada una de las fábricas)
Finalmente hago un main, para mandar a crear un objeto, para este ejemplo hice un pequeño switch, e inicialice una variable en 1, para crear un objeto TelefonoMovil, desde su fabrica.
Patrones de Diseño Software de Creación
Introducción
Los patrones de diseño software de creación proporcionan ayuda a la hora de crear objetos
desde el punto de vista de proporcionar un apopyo en la toma de decisiones, incluso cuando
esta toma de decisiones sea de forma dinámica.
Gracias a ello, ayudan a estructurar y encapsular estas decisiones. Hay ocasiones en la que
nos encontraremos con que sólo existe un patrón adecuado; otras en las que varios podrán
ayudarnos; y otras en que se pueden combinar múltiples patrones convenientemente.
Un patrón de creación asociado a clases usa la herencia para variar la clase que se instancia,
mientras que un patrón de diseño software de creación asociado a objetos delegará la
instanciación a otro objeto.
Hay dos formas de clasificar los patrones de diseño software de creación basándose en las
clases de objetos que se crean. Una es clasificar las clases que crean los objetos (Factory
Method), y la otra forma está relacionada con la composición de objetos (definir un objeto
que es responsable de conocer las clases de los objetos producto). En esta característica se
apoyan los patrones Abstract Factory, Builder o Prototype.
En muchas ocasiones los patrones de creación compiten en su función. Por ejemplo, hay
casos donde los patrones de creación Protoype y Abstract Factory puede utilizarse
indistintamente. En otras ocasiones Builder puede usar a los otros patrones para implementar
los componentes que construye.
A continuación, definiremos algunos de los patrones de diseño software de creación más
habituales.
Abstract Factory
Nos encontramos frente a un problema en el que debemos crear diferentes objetos, todos
pertenecientes a la misma familia, como puede ser el sistema de librerías necesarias para
crear interfaces gráficas. Visto esto podríamos decir que lo que intenta solucionar el patrón
de diseño software de creación Abstract Factory es crear diferentes familias de objetos. El
patrón Abstract Factory, por tanto, se recomienda cuando se atisba la inclusión de nuevas
familias de productos en un futuro, pero resultaría contraproducente si que necesita añadir
nuevos productos o modificar los existentes, ya que tendría repercusión en todas las familias
creadas.
Según esto, podemos decir que los componentes típicos del patrón Abstract Factory es la
siguiente:
Cliente: Entidad que llamará a la fábrica adecuada que necesite para crear uno de los objetos que provee dicha factoría, es decir, intentará obtener una instancia de alguno de los productos que entren en juego (ProductoA, ProductoB).
AbstractFactory: Definición de la interfaz que usarán las diferentes factorías. Como mínimo, debe ofrecer un método para la obtención de cada objeto que se pueda crear. ("crearProductoA()" y "crearProductoB()")
Concrete Factories: Aquí se representarán las diferentes familias de productos. Provee la instancia concreta del objeto que se encarga de crear.
Abstract Product: Definirá las interfaces para la familia de productos genéricos. En el diagrama son "ProductoA" y "ProductoB". El cliente trabajará directamente sobre esta interfaz, que será implementada por los diferentes productos concretos.
Concrete Product: Se encargará de la implementación específica de los diferentes productos.
Este sería el diagrama de clases general del patrón de creación Abstract Factory:
Esquema del patrón Abstract Factory
En este enlace podrá consultar un código de ejemplo en Java del patrón de creación
Abstract Factory.
Factory Method
Este patrón de diseño software de creación consiste en utilizar una clase constructora
abstracta (similar al concepto del patrón Abstract Factory) con unos métodos definidos y
otro(s) abstracto(s): el(los) dedicado(s) a la construcción de objetos de un subtipo
determinado.
Como vemos, es una simplificación del Abstract Factory, en la que la clase abstracta tiene
métodos concretos que se relacionan con los abstractos, de modo que según usemos una u
otra "hija" de esta clase abstracta, tendremos uno u otro comportamiento.
El patrón de diseño software de creación Factory Method puede ser usado cuando:
La creación de un objeto impide su reutilización sin una importante duplicación de código.
La creación de un objeto requiere acceso a la información o recursos que no deberían estar contenidos en la clase de composición.
La administración de la duración de los objetos generados debe ser centralizada para garantizar un comportamiento coherente en la aplicación.
Por tanto, los componentes del patrón de creación Factory Method sería:
Product: define una interfaz de un objeto que metodo Factory creara. ConcreteProduct: implementa la interfaz Product para crear un producto en concreto. Creator: declara el metodo factory que devolvera un objeto del tipo product. ConcreteCreator: sobre escribe e metodo factory del creator devoler una intancia de
un producto en concreto (ConcreteProduct).
Este sería el diagrama de clases general de este patrón de creación:
Esquema del patrón Factory Method
En este enlace podrá consultar un código de ejemplo en Java del patrón de creación
Factory Method.
Prototype
El patrón de diseño de software de creación Prototype, sirve para crear un duplicado de un
objeto, clonando, para ello, una instancia de ese objeto que ya haya sido creada. Para ello, el
patrón tiene que especificar el tipo de objeto que quiere clonar, creando así un 'prototipo' de
esa instancia. Este tipo o clase de objetos deberá contener en su interfaz el procedimiento
que permita solicitar esa copia, siendo desarrollado luego por las clases concretas del patrón
que deseen crear ese clon.
Como podemos ver, la principal razón de uso de este patrón de diseño software de creación
es crear las distintas clases de objetos que necesite el sistema, y hacerlo en el momento y
entorno adecuados. Eso sí, la lógica y diseño que necesite el sistema para la ejecución y
decisión de la creación de estos objetos copia, se hace de forma independiente al patrón,
siendo éste referido cuando el fragmento de código pertinente solicite una copia del objeto
que necesite. Cabe destacar que hacer una 'copia' significa crear otra instancia del objeto
(siempre que este tenga la funcionalidad de clonarse) con las particularidades necesarias en
ese instante.
Desacar también, que el API de Java dispone de interfaz Cloneable que facilita la
implementación de este patrón, haciéndola compatible con otros prototipos que se
encuentran en las diferentes librerías de Java.
Este sería el diagrama de clases general del patrón:
Esquema del patrón Prototype
Visto esto, los actores que intervienen en el patrón de creación Prototype, son:
Cliente: actor solicitante de la creación (clonación) de los nuevos objetos a partir de los prototipos.
Prototipo Concreto: actor (clase) que presenta unas características concretas que serán reproducidas en los nuevos objetos y que presenta la implementación necesaria para clonarse.
Prototipo: declara una interfaz, al a que accede el cliente, que sirve para la clonación de objetos.
En este enlace podrá consultar un código de ejemplo en Java del patrón de creación
Prototype.
Singleton
El patrón de diseño de software de creación Singleton (haciendo referencia a una instancia
única) busca restringir la creación de objetos pertenecientes a una clase o el valor de un tipo
a un único objeto. Su intención es garantizar que una clase sólo sea instanciada una vez y,
además, proporcionar un único punto de acceso global a la misma. Esto lo consigue gracias a
que es la propia clase la responsable de crear esa única instancia, (declarando el constructor
de la clase como privado) y a que se permite el acceso global a dicha instancia mediante un
método de clase.
Para implementar el patrón singleton hay que crear un método que instancie al objeto sólo
si todavía no existe ninguna otra instancia. Para asegurar que no vuelva a ser instanciado, se
limita al constructor con atributos protegidos o privados. Por esto, la implementación del
patrón puede ser complicada en programas multihilo, ya que si dos o más hilos de ejecución
instanciaran la clase al mismo tiempo sólo uno de ellos debería lograr crear el objeto. La
solución clásica para este problema es utilizar exclusión mutua en el método de creación de
la clase que implementa el patrón. Ejemplos de situaciones habituales en las que convendría
aplicar este ejemplo de patrón de diseño son aquellas en las que la clase principal busca
controlar el acceso a un recurso único (como puede ser el ratón o un archivo abierto en modo
exclusivo) o cuando cierto tipo de datos debe estar disponible para todos los demás objetos.
Este sería el diagrama de clases general del patrón de creación Singleton:
Abstract FactoryEste patrón crea diferentes familias de objetos. Su objetivo principal es soportar múltiples estándares que vienen definidos por las diferentes jerarquías de herencia de objetos. Es similar al Factory Method, sólo que esta orientado a combinar productos.
Se debe utilizar este patrón cuando: Un sistema se debe configurar con una de entre varias familias de productos.
Una familia de productos relacionados están hechos para utilizarse juntos.
Diagrama UML
AbstractFactory: declara una interfaz para la creación de objetos de productos abstractos.ConcreteFactory: implementa las operaciones para la creación de objetos de productos concretos.AbstractProduct: declara una interfaz para los objetos de un tipo de productos.ConcreteProduct: define un objeto de producto que la correspondiente factoría concreta se encargaría de crear, a la vez que implementa la interfaz de producto abstracto.Client: utiliza solamente las interfaces declaradas en la factoría y en los productos abstractos. Una única instancia de cada FactoryConcreto es creada en tiempo de ejecución. AbstractFactory delega la creación de productos a sus subclases FactoryConcreto.
Ahora que explique que rol ocupa cada uno en el diagrama, les pido un poco de atención en lo siguiente: veamos que relación tienen los FactoryConcretos con respectos a los productos. Esto es, FactoryConcreto1 crea una relación entre un producto de la familia A y un producto de la familia B. Y, por otro lado, tenemos que el FactoryConcreto2 crea una relación entre otros dos productos de ambas familias.Esto ya debería darnos una pista sobre el funcionamiento del AbstractFactory: se crea una clase por cada relación que necesitemos crear. Esto quedará más claro en el ejemplo a continuación.
Ejemplo
Hagamos de cuenta que tenemos dos familias de objetos:1) La clase TV, que tiene dos hijas: Plasma y LCD.2) La clase Color, que tiene dos hijas: Amarillo y Azul (los mejores colores, sin duda! ).
Más alla de todos los atributos/métodos que puedan tener la clase Color y TV, lo importante aquí es destacar que Color define un método abstracto: public abstract void colorea(TV tv);
Este método es la relación que une las dos familias de productos.Dado que es un método
abstracto, Azul debe redefinirlo:
public void colorea(TV tv) {System.out.println("Pintando de azul el "+ tv.getDescripcion());}
Lo mismo ocurre con Amarillo:
public void colorea(TV tv) {System.out.println("Pintando de amarillo el "+ tv.getDescripcion());}
Bien, veamos las clases correspondientes antes de continuar con nuestros ejemplo.
No es necesario implementar Clonable, no se lo necesita para este patrón.
Escenario: nuestra empresa se dedica a darle un formato estético específico a los televisores LCD y Plasma. Se ha decidido que todos los LCD que saldrán al mercado serán azules y los plasma serán amarillos. Ahora bien, una solución simple sería en la clase Azul colocar el LCD y en la clase Amarillo colocar el Plasma y todo funcionaría de maravillas. ¿Cual sería el problema? Que esta todo hardcodeado. Esto quiere decir que el hecho de que los LCD sean azules y los plasmas amarillos es una decisión del negocio y, como tal, puede variar (y de hecho el negocio varía constantemente).Por ejemplo, que pasa si mañana Se agrega otro color o me cambian el color del LCD o mucho peor, ¿que pasa si se crea otro producto LED y también se lo quiere pintar de Azul?Para evitar un dolor de cabeza conviene separar estas familias y utilizar el Abstract Factory:
Y los FactoryConcretos, que relacionan las familias:
Para ordenar un poco las cosas voy a crear un gestor de factorias:
Y, por último el main:
Consecuencias Se oculta a los clientes las clases de implementación: los clientes manipulan los objetos a través de las interfaces o clases abstractas.
Facilita el intercambio de familias de productos: al crear una familia completa de objetos con una factoría abstracta, es fácil cambiar toda la familia de una vez simplemente cambiando la factoría concreta.
Mejora la consistencia entre productos: el uso de la factoría abstracta permite forzar a utilizar un conjunto de objetos de una misma familia.
Como inconveniente podemos decir que no siempre es fácil soportar nuevos tipos de productos si se tiene que extender la interfaz de la Factoría abstracta.
Ejemplo Patrón Abstract Factory
Siguiendo con la secuencia de entradas sobre patrones de diseño, en esta ocasión realizaremos un ejemplo usando el Patrón Abstract Factory.......... es uno de esos ejemplos simples pero que enmarcan el objetivo del patrón.......
Que es?
Antes que nada debemos saber que existe un patrón llamado Factory el cual permite delegar en una clase la responsabilidad de crear objetos de otras clases, basados en esto Podemos decir que el Abstract Factoryes una nueva fase de Factory, Teniendo así una
Fabrica de Objetos donde la creación es transparente para la clase que los solicita.
Debemos saber entonces que el patrón Abstract Factory nos brinda una interfaz para crear familias de Objetos relacionados sin tener que especificar sus clases concretas desde la clase cliente (Clase que los solicita)
El problema
Se solicita la creación de diferentes vehículos de transporte (Buses, Busetas y Taxis) sin que se especifique en detalle la forma de su creación.
La solución.
Utilizamos el patrón Abstract Factory para independizar la forma como crearemos los objetos, de esta manera creamos familias de objetos de tipo Vehículo delegando el proceso y sin tener que entrar en detalles desde la clase solicitante.
La Aplicación.
Una vez mas trabajamos con un ejemplo simple, veremos una aplicación pequeña que permite al usuario crear familias de vehículos de 3 tipos diferentes, Buses, Busetas y Taxis, tan solo presentamos unas opciones de selección donde escogeremos que Objeto crear, he internamente por medio del Patrón de Diseño ejecutamos el proceso de creación....
Con este patrón revivimos Conceptos Básicos de Programación Orientada a Objetos tales como Las Interfaces, métodos Abstractos, Herencia, polimorfismo entre otros (si no los conocen los invito a darles una mirada aquí)...
En General la Aplicación se divide en Clases Fabricas que permiten hacer el llamado a la creación de Objetos, Interfaces que permiten aplicar conceptos como la Herencia y elPolimorfismo, también contamos con clases Concretas que representan los Objetos que crearán las Fabricas y por ultimo la clase principal que permitirá delegar las solicitudes para iniciar el proceso de creación.... Veamos!!!
Las Interfaces.
Interface Vehiculo.
Esta Interface es común para todos los vehículos de nuestra fabrica, en ella se declaran 2 métodos abstractos que serán comunes para los objetos a crear, sin importar si son Buses, Busetas o Taxis (Sabemos que por regla todos los métodos de una interfaz son abstractos, por ello no es necesario declararlos como tal)
1
2
3
4
5
6
7
package interfaces;
/**
* interfaz donde se establece el codigo del servicio
* @author chenao
*/
public interface Vehiculo
{
8
9
10
11
public void codigoDeVehiculo();
public int generarCodigo();
}
Interface VehiculoDeTransporte.
Esta Interface será implementada por las diferentes fabricas de de vehículos de la aplicación, cuenta con el método abstracto crearVehiculo() que será común para cada fabrica y como su nombre lo dice, le permitirá a cada una implementar la lógica para crear sus objetos concretos.
1
2
3
4
5
6
7
8
9
package interfaces;
/**
* interfaz que establece la creacion de un servicio
* @author chenao
*/
public interface VehiculoDeTransporte {
public Vehiculo crearVehiculo();
}
Las Fabricas.
Se componen por la Fabrica de Vehículos Principal que hace el llamado a las fabricas de Objetos Concretos..... estas implementan la interface VehiculoDeTransporte permitiendo crear los vehículos del tipo correspondiente y asignar el respectivo código de creación.....
Clase FabricaDeVehiculos.
Esta clase sera la Fabrica Principal cuenta con un método estático que permitirá la creación de los diferentes tipos de vehículos, aplicamos el concepto de polimorfismo para ejecutar el llamado a la Fabrica correspondiente y crear el objeto concreto solicitado por el cliente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package fabricas;
import interfaces.Vehiculo;
import interfaces.VehiculoDeTransporte;
/**
* Clase que permite la creacion de un servicio
* @author chenao
*
*/
public class FabricaDeVehiculos {
public static void crearFabricaDeVehiculo(VehiculoDeTransporte factory){
/**Aplicamos Polimorfismo*/
Vehiculo objetoVehiculo= factory.crearVehiculo();
objetoVehiculo.codigoDeVehiculo();
}
}
Clase FabricaBuses.
1
2
3
4
5
6
7
8
package fabricas;
import interfaces.Vehiculo;
import interfaces.VehiculoDeTransporte;
import javax.swing.JOptionPane;
import clases.Bus;
/**
9
10
11
12
13
14
15
16
17
18
19
20
21
* Clase que permite la creacion de un objeto Bus
* @author chenao
*
*/
public class FabricaBuses implements VehiculoDeTransporte{
public Vehiculo crearVehiculo() {
Bus miBus=new Bus();
miBus.setCodigo(miBus.generarCodigo());
JOptionPane.showMessageDialog(null, "Se ha creado un nuevo Objeto Bus ");
return miBus;
}
}
Clase FabricaBusetas.
1
2
3
4
5
6
7
8
9
10
11
12
package fabricas;
import interfaces.Vehiculo;
import interfaces.VehiculoDeTransporte;
import javax.swing.JOptionPane;
import clases.Buseta;
/**
* Clase que permite la creacion de un objeto Buseta
* @author chenao
*
*/
13
14
15
16
17
18
19
20
21
22
public class FabricaBusetas implements VehiculoDeTransporte{
@Override
public Vehiculo crearVehiculo() {
Buseta miBuseta=new Buseta();
miBuseta.setCodigo(miBuseta.generarCodigo());
JOptionPane.showMessageDialog(null, "Se ha creado un nuevo Objeto Buseta");
return miBuseta;
}
}
Clase FabricaTaxis.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package fabricas;
import interfaces.Vehiculo;
import interfaces.VehiculoDeTransporte;
import javax.swing.JOptionPane;
import clases.Taxi;
/**
* Clase que permite la creacion de un objeto Taxi
* @author chenao
*
*/
public class FabricaTaxis implements VehiculoDeTransporte{
@Override
public Vehiculo crearVehiculo() {
Taxi miTaxi=new Taxi();
16
17
18
19
20
21
22
miTaxi.setCodigo(miTaxi.generarCodigo());
JOptionPane.showMessageDialog(null, "Se ha creado un nuevo Objeto Taxi");
return miTaxi;
}
}
Las Clases Concretas.
Representan las clases de las que se instanciarán los objetos de tipo Vehículo (Buses, Busetas y Taxis) así como la clase principal que permite delegar las funcionalidades.....Las clases Bus, Buseta y Taxi Implementan la Interface Vehículo, y cada una permite generar un código aleatorio para identificar el vehículo creado....
Clase Bus.
1
2
3
4
5
6
7
8
9
10
11
12
13
package clases;
import interfaces.Vehiculo;
import javax.swing.JOptionPane;
/**
* clase que establece el codigo del servicio de buses
* @author chenao
*
*/
public class Bus implements Vehiculo{
private int codigo;
public int generarCodigo()
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
int codigoBus=(int) (Math.random()*9999);
return codigoBus;
}
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public void codigoDeVehiculo() {
JOptionPane.showMessageDialog(null,"El Codigo del Bus es : "+getCodigo());
}
}
Clase Buseta.
1
2
3
4
5
6
7
8
9
10
package clases;
import interfaces.Vehiculo;
import javax.swing.JOptionPane;
/**
* clase que establece el codigo del servicio de busetas
* @author chenao
*/
public class Buseta implements Vehiculo{
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private int codigo;
public int generarCodigo()
{
int codigoBuseta=(int) (Math.random()*9999);
return codigoBuseta;
}
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
@Override
public void codigoDeVehiculo() {
JOptionPane.showMessageDialog(null,"El Codigo de la Buseta es:"+getCodigo());
}
}
Clase Taxi.
1
2
3
4
5
6
7
package clases;
import interfaces.Vehiculo;
import javax.swing.JOptionPane;
/**
* clase que establece el codigo del servicio de taxis
* @author chenao
*/
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Taxi implements Vehiculo{
private int codigo;
public int generarCodigo()
{
/**Generamos un codigo aleatorio para el taxi*/
int codigoTaxi=(int) (Math.random()*9999);
return codigoTaxi;
}
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
@Override
public void codigoDeVehiculo() {
JOptionPane.showMessageDialog(null,"El Codigo del Taxi es : "+getCodigo());
}
}
Clase Principal.
Esta clase permite iniciar el sistema, en ella creamos las instancias de Fabricas y mediante un menú de opciones se define y delega que Fabrica inicia el proceso de creación...
1
2
package principal;
import javax.swing.JOptionPane;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import fabricas.FabricaBuses;
import fabricas.FabricaBusetas;
import fabricas.FabricaDeVehiculos;
import fabricas.FabricaTaxis;
/**
* clase principal del aplicativo donde se establecen las instancias
* de las fabricas
* @author chenao
*
*/
public class Principal {
public static void main(String[] args)
{
FabricaBusetas busetas=new FabricaBusetas();
FabricaTaxis taxi=new FabricaTaxis();
FabricaBuses buses=new FabricaBuses();
String cad="",salida;
cad+="Ingrese la opción correspondiente para obtener el codigo del servicio\n";
cad+="1. Codigo servicio de Taxis\n";
cad+="2. Codigo servicio de Buses\n";
cad+="3. Codigo servicio de Busetas\n\n";
try {
do {
try
{
int opcion=Integer.parseInt(JOptionPane.showInputDialog(cad));
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
switch (opcion)
{
case 1:FabricaDeVehiculos.crearFabricaDeVehiculo(taxi);
break;
case 2:FabricaDeVehiculos.crearFabricaDeVehiculo(buses);
break;
case 3:FabricaDeVehiculos.crearFabricaDeVehiculo(busetas);
break;
default:JOptionPane.showMessageDialog(null,"No es un valor de consultavalido");
break;
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null,"No es un parametro de consulta valido");
}
salida=JOptionPane.showInputDialog("Desea consultar otro codigo? S/N");
} while (salida.toUpperCase().equals("S"));
} catch (Exception e) {
JOptionPane.showMessageDialog(null,"Bye!!!");
}
}
}
Conclusiones.
Y Listo!!! Como vemos es un Patrón que al principio puede sonar un poco intimidante pero a medida que vamos trabajando con el nos damos
cuenta de como podemos sacarle provecho a su aplicación...
Podemos evidenciar también el uso de varios conceptos de programación orientada a objetos siendo los patrones de diseño un gran ejemplo de su aplicación....
Programa para resolver ecuaciones lineales por los metodos de Jacobi o de Gauss-Seidel
function metodo=metodo()format longdisp('¿QUE METODO DESEA UTILIZAR PARA RESOLVER EL PROBLEMA?');disp('1.-MÉTODO DE JACOBI');disp('2.-MÉTODO DE GAUSS');disp('3.-SALIR');n=input('SELECCIONE UNA OPCION: ');if n==1num=input('INTODUCE EL NUMERO DE ECUACIONES: ');A=input('INTRODUCE LA MATRIZ DE COEFICIENTES: ');b=input('INTRODUCE LA MATRIZ DE COEFICIENTES INDEPENDIENTES: ');z=input('INTRODUZCA EL NUMERO DE ITERACIONES: ');X0=zeros(1,num);for f=1:zfor i=1:numsuma=0;for j=1:numif i~=jsuma=suma+A(i,j)*X0(j);endendX(i)=(b(i)-suma)/A(i,i);fprintf('%10.4f',X(i));endfprintf('\n');X0=X;endelseif n==2num=input('INTRODUCE EL NUMERO DE ECUACIONES: ');A=input('INTRODUCE LA MATRIZ DE COEFICIENTES: ');b=input('INTRIODUCE LA MATRIZ DE COEFICIENTES INDEPENDIENTES: ');z=input('INTRODUZCA EL NUMERO DE ITERACIONES: ');X0=zeros(1,num);X=X0;for f=1:zfor i=1:numsuma=0;for j=1:numif i~=jsuma=suma+A(i,j)*X(j);endendX(i)=(b(i)-suma)/A(i,i);fprintf('%10.4f', X(i));endX0=X;
fprintf('\n');endelseif n==3return;elsedisp('ERROR');end
MÉTODO DE JACOBI y MÉTODO DE GAUSS-SEIDELPara el método de Jacobi, considere un sistema Ax=b
Sea A = D - E - F, donde D es la diagonal de A, -E la triangula inferior y -F la
triangular superior.Así, la sucesión que se construye con este método iterativo será:Ax = b(D-E-F)x = b Dx = (E+F)x + b
x(k) = D-1(E+F)x(k-1) + D-
1bEl siguiente programa resuelve mediante el método de Jacobi un sistema de ecuaciones Ax=b con un error menor que una tolerancia dada tol. Note que el programa necesita un dato inicial x0. Además, el programa se detiene si se alcanza un número máximo de iteraciones maxit sin que se satisfaga el criterio de convergencia.
function [x,iter]=jac(A,b,x,tol,maxit)
N=diag(diag(A));
P=N-A; corr=1; errest=1; iter=0;
while abs(errest)>tol & iter<maxit
iter=iter+1;
x0=x;
corr0=corr;
x=N\(P*x0+b);
corr=norm(x-x0,inf);
normest=corr/corr0;
if normest>=1 & iter>=2
error('norma de la matriz de iteración > 1')
end
errest=normest/(1-normest)*corr;
end
iter
Ejemplo: Resuelva Ax(0)=b, con una aproximación inicial x(0)=[0 0 0]'
>> A=[5 -2 1;-1 -7 3;2 -1 8];>> x=[0 0 0]';>> b=[3 -2 1]';>> tol=10^-6;>> maxit=200;>> jac(A,b,x,tol,maxit)
iter=
13
ans=
0.6763
0.1799
-0.0216
Para el MÉTODO DE GAUSS-SEIDEL, modificar N y P:N=tril(A)P=N-A
Codigo Jacobi Matlab Publicado en 26 enero, 2010de dgm116
function[]=jacobi(y,v)
%funcion que soluciona un sistema de ecuaciones simultaneas
[r,c]=size(y);%r guarda el numero de renglones y c el numero de columnas
d=diag(y);%d sera un vector el cual contendra los elementos de la
%diagonal principal de la matriz formada por el sistema
%de ecuaciones
h=0;%h servira de contador
z=0;%z sera el valor que usaremos para condicionar
k=0;
for i=1:r%Inicio de despeje de incognitas
for j=1:c
if j~=i
x(i,j)=[-y(i,j)./d(i)];%x sera una matriz la cual contendra
%en sus renglones nuestras incognitas
%despejadas
end
end
end %incognitas despejadas
while z~=1%ciclo que se repetira hasta encontrar el valor de las incognitas
for i=1:r%este ciclo nos servira para controlar el numero de
%renglon en que se este analizando y asi evaluar las
%incognitas
%despejadas y obtener los nuevos valores que se utilizaran
%para evaluar dichas incognitas
f(i)=0;%la posicion i del vector f se le asignara cero
%para evitar una acomulacion
for j=1:c%ciclo que nos servira para encontrar los nuevos valores
%en los que se evaluara nuestras incognitas
if j~=c%condicion para evitar multiplicar el valor constante
f(i)=f(i)+(x(i,j).*v(j));%el vector f tomara los nuevos
%valores en los se volveran a
%evaluar las incognitas despejadas
else
f(i)=f(i)+(x(i,j));
end
end
end
for i=1:r
if f(i)==v(i)%se comparan los valores del vector f con los
%del vector v
h=h+1;%si se cumple la condicion el contador aumenta
end
end
for i=1:r
v(i)=f(i);%el vector v adquiere los nuevos valores obtenidos
%anteriormente
end
if h==r
z=1;%si el contador es igual al numero de renglones quiere decir
%que los valores utilizados anteriormente son iguales a los
%acabados de obtener
else
h=0;%si no el contador regresa a cero
end
Top Related