Documente Academic
Documente Profesional
Documente Cultură
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
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
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
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
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
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
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:
Laboratorio de P y L 2013
}
}
return tr;
Laboratorio de P y L 2013
Laboratorio de P y L 2013
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
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
public class LocaleArgentinaFactory extends AbstractLocaleFactory{ public LocaleArgentinaFactory(){ this.pais=this.AR; } public Traductor createTraductor() { return TraductorFactory.createTraductor("espanol"); }
Subclase de AbstractFactory
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
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