Sunteți pe pagina 1din 25

Laboratorio de Programacin y Lenguajes

Tema: Ejemplos Abstract factory y Factory pattern


UNPSJB Sede Ushuaia, 2012

Patrones creacionales

Los patrones creacionales (creational patterns) son aquellos que tienen que ver con la creacin de objetos. La razn de ser de estos patrones es para facilitar, ordenar, o ayudar en la creacin de objetos. Dependiendo del lenguaje de programacin que estemos utilizando, generalmente crearemos un objeto as: Objeto o = new Objeto(). En los patrones creacionales probablemente se crea un un objeto Objeto o = ObjectoFactory.getInstance(x), o algo parecido.

Laboratorio de P y L 2013

Patrones creacionales - Factory


Propsito

Crea objetos sin exponer la lgica de instanciacin al cliente. Refiere al nuevo objeto creado a travs de una interface comn.

Laboratorio de P y L 2013

Patrones creacionales

Supongamos se nos encarga crear un traductor que devuelva los nmeros del cero al diez en tres idiomas: ingls, espaol, y alemn. Existen muchsimas maneras de hacer esto. Se necesita un mtodo que reciba un entero entre 0 y 10 y que devuelva una cadena con el nombre de dicho nmero en el idioma que se est trabajando. Una manera podra ser la del siguiente ejemplo:

Laboratorio de P y L 2013

public class MainClient { public MainClient(){ } public traducirNumero(String idioma, int numero){ if (idioma.equals("espaol")){ switch (numero){ case 0: return "uno"; case 1: return "dos"; .... } } if (idioma.equals("english")){ switch (numero){ case 0: return "one"; case 1: return "two"; .... } } if (idioma.equals("deutsch")){ switch (numero){ case 0: return "eins"; case 1: return "zwei"; .... } } }//traducirNumero public static void main(String args[]){ MainClient mc = new MainClient(); System.out.println(mc.traducirNumero("espanol",1)); Laboratorio de P y L 2013 }

Factory pattern

Esta solucin parece funcionar, y de hecho lo hace. Pero imaginemos que ahora nos dicen que desean la traduccin de ms nmeros? Y en diferentes idiomas.. Sin duda el cdigo comenzar a crecer. Y claro, ahora tendremos que agregar cdigo de lgica para cada idioma para escribir nmeros como 752, etc. Lo primero que se nos ocurre es una herencia. Definiremos una clase abstracta Traductor, y para cada idioma haremos una subclase de Traductor

public abstract class Traductor{ public abstract String traducirNumero(int numero); }


Laboratorio de P y L 2013

Extendiendo Traductor-Espaol
public class TraductorEspanol extends Traductor {
public TraductorEspanol(){ super(); ... } public String traducirNumero(int numero){ switch(numero){ case 1: return "uno"; case 2: return "dos"; ... } } }

Laboratorio de P y L 2013

Extendiendo Traductor-Ingls
public class TraductorIngles extends Traductor {
public TraductorIngles(){ super(); ... } public String traducirNumero(int numero){ switch(numero){ case 1: return "one"; case 2: return "two"; ... } } } Y as agregaramos el traductor de alemn
Laboratorio de P y L 2013

Utilizacin del traductor

Para utilizar un traductor, se escribira:

Traductor t = new TraductorEspanol(); t.traducirNumero(1);

La clase MainClient ahora se vera >>>>

Laboratorio de P y L 2013

public class MainClient {


public String traducirNumero(String idioma, int numero){ Traductor traductor = null; if (idioma.equals("espaol")){ traductor = new TraductorEspanol(); } if (idioma.equals("ingles")){ traductor = new TraductorIngles(); } if (idioma.equals("aleman")){ traductor = new TraductorAleman(); } String toReturn traductor.traducirNumero(); return toReturn; }//traducirNumero public static void main(String args[]){ MainClient mc = new MainClient(); System.out.println(mc.traducirNumero("espanol",1)); } }//de la clase
Laboratorio de P y L 2013

Incorporando un TraductorFactory

Podramos agregar el traductor para el francs muy fcilmente. Adems hemos escondido la manera en la que traducimos, ya que cada Traductor concreto se encarga de ello. Pero todava no utilizamos Factory Pattern. La clase MainClient() no debera elegir la instancia de Traductor que necesita usar (imaginar que se usa el traductor en 100 lugares). El patrn de fbrica -factory pattern- esconde esa lgica. Vamos a agregar ahora una fbrica de traductores

Laboratorio de P y L 2013

El Factory Traductor
public class TraductorFactory { public TraductorFactory(){
} public static Traductor createTraductor(String idioma){ Traductor traductor = null; if (idioma=="espaol"){ traductor = new TraductorEspanol(); } if (idioma=="english"){ traductor = new TraductorIngles(); } if (idioma=="deutsch"){ traductor = new TraductorAleman(); } return traductor;

} }//de la clase

Laboratorio de P y L 2013

Uso de TraductorFactory

Qu hace TraductorFactory? Elige, en base a los argumentos dados en este caso el idioma- qu clase de traductor se instanciar. El MainClient quedara as:

public class MainClient { String idioma; public static void main(String []args){ Traductor traductor = TraductorFactory.createTraductor("espanol"); System.out.println(traductor.traducirNumero(1) ); }//main }//de la clase

Laboratorio de P y L 2013

Consecuencias del uso del Factory


MainClient se ha visto reducido, y su cdigo es muy fcil de leer. Quien quiera usar un traductor simplemente har llamar a dicha clase. MainClient sabe el idioma que eligieron, pero no sabe qu subclase de Traductor instanciar, pero sabiendo el idioma, TraductorFactory sabe exactamente qu instancia de Traductor crear. Si la aplicacin desea cambiar de idioma simplemente le enva otro parmetro a MainClient y listo. Tambin agregar idiomas es ms manejable que antes. El Factory Pattern esconde al usuario final del cdigo la decisin de qu subclase instanciar y promueve el encapsulamiento de las partes ms variables del sistema. En trminos generales, una fbrica abstracta consiste de las siguientes partes: - Un cliente, que es el que llama a la fbrica (en nuestro caso MainClient). - Una fbrica, que decide la clase a instanciar (TraductorFactory). - Un producto, lo que la fbrica devuelve (para nosotros las instancias de Traductor).
Laboratorio de P y L 2013

Consecuencias del uso del Factory


MainClient se ha visto reducido, y su cdigo es muy fcil de leer. Quien quiera usar un traductor simplemente har llamar a dicha clase. MainClient sabe el idioma que eligieron, pero no sabe qu subclase de Traductor instanciar, pero sabiendo el idioma, TraductorFactory sabe exactamente qu instancia de Traductor crear. Si la aplicacin desea cambiar de idioma simplemente le enva otro parmetro a MainClient y listo. Tambin agregar idiomas es ms manejable que antes. El Factory Pattern esconde al usuario final del cdigo la decisin de qu subclase instanciar y promueve el encapsulamiento de las partes ms variables del sistema. En trminos generales, una fbrica abstracta consiste de las siguientes partes: - Un cliente, que es el que llama a la fbrica (en nuestro caso MainClient). - Una fbrica, que decide la clase a instanciar (TraductorFactory). - Un producto, lo que la fbrica devuelve (para nosotros las instancias de Traductor).
Laboratorio de P y L 2013

Abstract Factory. Ejemplo


Reloj que muestra la hora actual. Como sabemos, la hora puede ser desplegada en formato de 24Hrs o puede ser desplegada en formato AM/PM. Recordando que es a manera de ejemplo, se utiliza la clase Date de una manera poco sencilla. Como en el caso del traductor, haremos una clase abstracta de Reloj y dos implementaciones para cada una de los formatos, y una clase que contenga el mtodo del Factory Method. La cosa quedara algo as:

public abstract class Reloj { }

abstract String dameLaHora();

Laboratorio de P y L 2013

Clase concreta Reloj Am-Pm


public class RelojAmPm extends Reloj{
public RelojAmPm(){ } public String dameLaHora() { Date d = new Date(); int hora = d.getHours(); int minutos = d.getMinutes(); int segundos = d.getSeconds(); String tr; if (hora<=12){ tr="Son las "+hora+":"+minutos+":"+segundos+" AM"; } else { tr="Son las "+(hora-12)+":"+minutos+":"+segundos+" PM"; }

}
}

return tr;

Laboratorio de P y L 2013

Clase concreta con formato 24 hs


public class Reloj24Hrs extends Reloj {
public String dameLaHora() { Date d = new Date(); int hora = d.getHours(); int minutos = d.getMinutes(); int segundos = d.getSeconds(); String tr; tr = "Son las " + hora + ":" + minutos + ":" + segundos + " "; } return tr;

Laboratorio de P y L 2013

Clase con el mtodo que elige instancias


public class RelojFactory { public static final int RELOJ_AM_PM=0; public static final int RELOJ_24_HRS=1;
public RelojFactory(){ } public static Reloj createReloj(int tipoDeReloj){ if (tipoDeReloj==RelojFactory.RELOJ_24_HRS){ return new Reloj24Hrs(); } if (tipoDeReloj==RelojFactory.RELOJ_AM_PM){ return new RelojAmPm(); } } }

return null;

Clase que contiene la el mtodo que elije las instancias. El parmetro que recibe el mtodo es un entero, que acepta los enteros especificados como constantes estticas en la clase. Esto se usa mucho para no estar adivinando los parmetros que acepta el mtodo
Laboratorio de P y L 2013

Clase cliente
public class MainClient {
public static void main(String[] args) { Reloj r = RelojFactory.createReloj(RelojFactory.RELOJ_24_HRS); System.out.println(r.dameLaHora()); }

Ej:En un proyecto cualquiera se nos pide hacer un sistema que despliegue la hora y los nmeros de la manera en la que se expresan en cada pas (una implementacin elemental de Locale de Java). Ejemplos prcticos: En Estados Unidos se despliegan los nmeros en ingls, y la hora en formato AM/PM; mientras que en Argentina se dicen los nmeros en espaol y la hora en formato de 24 Horas.

Laboratorio de P y L 2013

Creacin de la AbstractFactory

Creamos una AbstractFactory llamada Locale.

public abstract class AbstractLocaleFactory { public static final String US="ESTADOS_UNIDOS"; public static final String AR=ARGENTINA"; String pais; public abstract Traductor createTraductor(); public abstract Reloj createReloj(); //Traductor y Reloj son abstractas public String getPais(){ return this.pais; } public void setPais(String pais){ this.pais = pais; } }//Fbrica con un par de mtodos que devuelven un Laboratorio de P y L 2013 //Reloj y un traductor

Subclase de AbstractFactory

Creamos una LocaleArgentinaFactory.

public class LocaleArgentinaFactory extends AbstractLocaleFactory{ public LocaleArgentinaFactory(){ this.pais=this.AR; } public Traductor createTraductor() { return TraductorFactory.createTraductor("espanol"); }

public Reloj createReloj() { return RelojFactory.createReloj(RelojFactory.RELOJ_24_HRS ); } }


Laboratorio de P y L 2013

Subclase de AbstractFactory

Creamos la respectiva clase para EEUU.

public class LocaleEstadosUnidosFactory extends AbstractLocaleFactory{ public LocaleEstadosUnidosFactory(){ this.pais=this.US; } public Traductor createTraductor() { return TraductorFactory.createTraductor("ingles"); } public Reloj createReloj() { return RelojFactory.createReloj(RelojFactory.RELOJ_AM_PM) ; } }
Laboratorio de P y L 2013

El Cliente

public class MainClient { public static void main(String[] args) { Reloj reloj = null; Traductor traductor = null; AbstractLocaleFactory localeFactory = new LocaleArgentinaFactory(); reloj = localeFactory.createReloj(); traductor = localeFactory.createTraductor(); System.out.println("--------"); System.out.println("1="+traductor.traducirNumero(1)); System.out.println(reloj.dameLaHora()); } } El resultado de correr el codigo anterior es: 1=uno Son las 21:50:17

Laboratorio de P y L 2013

Para cambiar de pas El Cliente

public class MainClient { public static void main(String[] args) { Reloj reloj = null; Traductor traductor = null; AbstractLocaleFactory localeFactory = new LocaleEstadosUnidosFactory(); reloj = localeFactory.createReloj(); traductor = localeFactory.createTraductor(); System.out.println("--------"); System.out.println("1="+traductor.traducirNumero(1)); System.out.println(reloj.dameLaHora()); } } Y ahora el resultado de correr el codigo anterior es:

1=one 9:52:56 PM

Laboratorio de P y L 2013

S-ar putea să vă placă și