2010-04-23 17 views
5

Quiero saber cuándo necesitamos usar el patrón abstracto de fábrica.cuándo utilizar el patrón abstracto de fábrica?

Aquí hay un ejemplo, quiero saber si es necesario.

The UML

lo anterior es el patrón de fábrica abstracta, es recomendado por mi compañero de clase. Lo que sigue es mi implementación. No creo que sea necesario usar el patrón.

Y el siguiente es algunos códigos básicos:

package net; 

import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Properties; 



public class Test { 
    public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException { 
     DaoRepository dr=new DaoRepository(); 
     AbstractDao dao=dr.findDao("sql"); 
     dao.insert(); 
    } 
} 

class DaoRepository { 
    Map<String, AbstractDao> daoMap=new HashMap<String, AbstractDao>(); 
    public DaoRepository() throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException { 
     Properties p=new Properties(); 
     p.load(DaoRepository.class.getResourceAsStream("Test.properties")); 
     initDaos(p); 
    } 
    public void initDaos(Properties p) throws InstantiationException, IllegalAccessException, ClassNotFoundException { 
     String[] daoarray=p.getProperty("dao").split(","); 
     for(String dao:daoarray) { 
      AbstractDao ad=(AbstractDao)Class.forName(dao).newInstance(); 
      daoMap.put(ad.getID(),ad); 
     } 
    } 
    public AbstractDao findDao(String id) {return daoMap.get(id);} 

} 
abstract class AbstractDao { 
    public abstract String getID(); 
    public abstract void insert(); 
    public abstract void update(); 
} 
class SqlDao extends AbstractDao { 
    public SqlDao() {} 
    public String getID() {return "sql";} 
    public void insert() {System.out.println("sql insert");} 
    public void update() {System.out.println("sql update");} 
} 
class AccessDao extends AbstractDao { 
    public AccessDao() {} 
    public String getID() {return "access";} 
    public void insert() {System.out.println("access insert");} 
    public void update() {System.out.println("access update");} 
} 

y el contenido de la Test.properties es sólo una línea:

dao=net.SqlDao,net.SqlDao 

Así que cualquier ONT puede decirme si esto es necesario suitation ?


------------------- Se añade lo siguiente a explicar la verdadera suitation --------------

Uso el ejemplo de Dao porque es común, cualquiera lo sabe.

De hecho, lo que estoy trabajando ahora no está relacionado con el DAO, estoy trabajando para construir una web de servicios

, el serivce web contiene algunos algoritmos para chang un archivo a otro formato,

Por ejemplo: net.CreatePDF, net.CreateWord y etc., expone dos interfaces al cliente: getAlgorithms y doProcess.

getAlogrithoms devolverá todos los id. De los algoritmos, cada id. Se aplica al algoritmo correspondiente .

El usuario que llama al método doProcess también le proporcionará el ID de algoritmo que desea.

Todo el algoritmo amplía el AbstractAlgorithm que define un método run().

Puedo usar un AlogrithmsRepository para almacenar todos los algoritmos (de

el archivo de propiedades que config las clases Java concreta de los algoritmos por la web

administrador de servicios) .Es de decir, el DoProcess interfaz expuesta por el servicio web es

ejecutado por el alogrithm concreto.

me puede dar un ejemplo sencillo: 1) el usuario envía la solicitud getAlgorithms:

http://host:port/ws?request=getAlgorithms 

A continuación, el usuario recibirá una lista de algoritmos embebidos en un xml.

<AlgorithmsList> 
    <algorithm>pdf</algorithm> 
    <algorithm>word<algorithm> 
</AlgorithmsList> 

2) de usuario a enviar un DoProcess al servidor por:

http://xxx/ws?request=doProcess&alogrithm=pdf&file=http://xx/Test.word 

cuando el servidor recieve este tipo de requst, conseguirá la instancia algoritmo de hormigón de acuerdo con el parámetro de "algoritmo" (se pdf en esta solicitud) del AlgorithmRepostory. Y llame al método:

AbstractAlgorithm algo=AlgorithmRepostory.getAlgo("pdf"); 
algo.start(); 

A continuación, se enviará un archivo pdf al usuario.

BTW, en este ejemplo, cada algoritmo es similar al sqlDao, AccessDao. Aquí está la imagen:

The design image

Ahora, ¿el AlgorithmRepostory necesita usar la fábrica abstracta?

Respuesta

2

La principal diferencia entre los dos enfoques es que el superior utiliza diferentes fábricas DAO para crear DAO mientras que el inferior almacena un conjunto de DAO y devuelve referencias a los DAO en el repositorio.

El enfoque de fondo tiene un problema si varios subprocesos necesitan acceso al mismo tipo de DAO concurentemente ya que las conexiones JDBC no están sincronizadas.

Esto se puede solucionar haciendo que el DAO implemente un método newInstance() que simplemente crea y devuelve un nuevo DAO.

abstract class AbstractDao { 
    public abstract String getID(); 
    public abstract void insert(); 
    public abstract void update(); 
    public abstract AbstractDao newInstance(); 
} 
class SqlDao extends AbstractDao { 
    public SqlDao() {} 
    public String getID() {return "sql";} 
    public void insert() {System.out.println("sql insert");} 
    public void update() {System.out.println("sql update");} 
    public AbstractDao newInstance() { return new SqlDao();} 
} 

El repositorio puede utilizar el DAO de en el repositorio como fábricas para la DAO de devuelto por el repositorio (que me gustaría cambiar el nombre de fábrica en ese caso) como este:

public AbstractDao newDao(String id) { 
    return daoMap.containsKey(id) ? daoMap.get(id).newInstance() : null; 
} 

actualización

En cuanto a su pregunta, ¿su servicio web debe implementar una fábrica o puede usar el repositorio como describió?De nuevo, la respuesta depende de los detalles:

  • Para servicios web es normal esperan múltiples clientes simultáneos
  • Por lo tanto las instancias ejecutoras del proceso para dos clientes no deben influencia entre si
  • Lo que significa no deben haber compartido estado
  • Una fábrica ofrece una nueva instancia en cada solicitud, por lo que no se comparte el estado cuando se utiliza un patrón de fábrica
  • Si (y sólo si) los casos en su repositorio no tienen estado de su servicio web también puede utilizar el repositorio como usted la describe, para este que probablemente necesitan para crear instancias de otros objetos para ejecutar realmente el proceso basado en la solicitud parámetros pasados ​​
+0

@ rsp-Gracias por solucionar mi problema. De hecho, lo que quiero dejar en claro es que cuando se utiliza una fábrica abstracta, es decir, suponemos que las dos formas mencionadas anteriormente no pueden causar algunos problemas de hilos. bueno, si el problema no existe, ¿por qué usamos Abstract Factory? En el patrón Ab.Fatory, los diferentes productos son creados por diferentes fábricas, de la siguiente manera (la que usted arregló), los productos son creados por un Repositorio (el DaoRepository en el ejemplo), entonces, ¿cuál es la diferencia? Cuando el Repositorio crea una nueva instancia, tampoco sabe qué objeto está creando, ¿no es así? – hguser

+0

@hguser, como siempre depende del contexto. Si necesita crear una instancia de un conjunto de objetos que utiliza la aplicación, no hay nada de malo en un repositorio que crea instancias basadas en la configuración y distribuye referencias a estos objetos. En este caso, la "fábrica" ​​es parte de la inicialización del repositorio.Una fábrica de objetos que crea nuevas instancias es otro caso de uso, que podría cubrir más usos. – rsp

+0

@ rsp-Entonces, para la situación que agregué (el ejemplo del servicio web), si uno quiere usar la fábrica abstracta en el AlgorithmsRepository, ¿cómo implementarlo? Realmente quiero aclarar las diferencias con el mismo ejemplo. Gracias. – hguser

2

Si le preguntas a comparar 2 diseños de UML, UML segundo API de haber inconveniente siguiente:

  • persona que llama tiene que especificar explícitamente el tipo de DAO en llamada a getDAO(). En cambio, a la persona que llama no debería importarle el tipo de DAO con el que funcione, siempre que DAO cumpla con la interfaz. El primer diseño permite que quien llama simplemente llame a createDAO() y obtenga la interfaz para trabajar. De esta manera, el control de la cual utilizar es más flexible y la persona que llama no tiene esta responsabilidad, lo que mejora la coherencia general del diseño.
+0

Pero la fábrica abstracta también necesita atención de la persona que llama sobre el tipo. http://java.dzone.com/articles/design-patterns-abstract-factory En este artículo, según el método principal, el usuario debe saber que hay dos tipos, MsWindowsWidgetFactory y MACOSWindowsWidgetFactory. – hguser

+0

@hguser: en algún lugar de la cadena de llamadas, alguien necesita especificar el tipo, pero el llamante * inmediato * de una fábrica abstracta no necesita saber el tipo de fábrica. –

+0

@Jeff Sternal - http://dpaste.org/GyRC/ Línea 9 y 13, llamamos a la fábrica por la palabra "nueva". – hguser

0

Abstract Factory es útil si necesita separar múltiples dimensiones de opciones para crear algo.

En el caso de ejemplo común de sistemas de ventanas, desea hacer una familia de widgets para sistemas de ventanas surtidos, y crea una fábrica de concreto por sistema de ventana que crea widgets que funcionan en ese sistema.

En su caso de crear DAO, es útil si necesita crear una familia de DAO para las distintas entidades de su dominio y desea crear una versión "sql" y una versión de "acceso" de la totalidad familia. Este es el punto que tu compañero de clase intenta hacer, y si eso es lo que estás haciendo, es probable que sea una buena idea.

Si solo tiene una cosa que varía, es exagerada.

Cuestiones relacionadas