何时使用抽象工厂模式?

时间:2010-04-23 12:24:26

标签: java design-patterns factory-pattern

我想知道何时需要使用抽象工厂模式。

这是一个例子,我想知道是否有必要。

The UML

以上是抽象工厂模式,我的同学推荐。 以下是我的实施。我不认为有必要使用这种模式。

以下是一些核心代码:

    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");}
}

Test.properties的内容只有一行:

dao=net.SqlDao,net.SqlDao

所以任何事情都可以告诉我这种适应是否必要吗?


-------------------以下内容是为了解释真实的诉讼--------------

我用Dao的例子是因为它很常见,任何人都知道。

事实上,我现在正在工作的是与DAO无关,我正在努力构建一个Web

服务,web服务包含一些将文件转换为其他格式的算法,

例如:net.CreatePDF,net.CreateWord等,它向客户端公开两个接口:getAlgorithms和doProcess。

getAlogrithoms将返回所有算法的id,每个id都被转换为 相应的算法。

调用doProcess方法的用户还将提供他想要的算法ID。

所有算法都扩展了AbstractAlgorithm,它定义了run()方法。

我使用AlogrithmsRepository存储所有算法(来自

属性文件,它通过Web配置算法的具体java类

service admin)。也就是说,Web服务公开的接口DoProcess是

由具体的算法执行。

我可举一个简单的例子: 1)用户发送getAlgorithms请求:

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

然后用户将获得嵌入xml中的算法列表。

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

2)用户通过以下方式向服务器发送DoProcess:

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

当服务器接收到这种类型的请求时,它将根据AlgorithmRepostory中的“algorithm”参数(在此请求中为pdf)获取具体的算法实例。并调用方法:

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

然后将pdf文件发送给用户。

BTW,在这个例子中,每个算法类似于sqlDao,AccessDao。 这是图像:

The design image

现在,AlgorithmRepostory是否需要使用抽象工厂?

3 个答案:

答案 0 :(得分:2)

如果要求比较UML的2个设计,UML上的第2个API有以下缺点:

  • 调用者需要在调用getDAO()时明确指定DAO的类型。相反,只要DAO符合接口,调用者就不应该关心它所使用的DAO的类型。第一种设计允许调用者只需调用createDAO()并使用接口即可。这样控制使用哪个impl就更灵活,调用者没有这个责任,这提高了设计的整体连贯性。

答案 1 :(得分:2)

这两种方法的主要区别在于前者使用不同的DAO工厂来创建DAO,而底部的工厂存储一组DAO并返回对存储库中DAO的引用。

如果多个线程需要访问同一类型的DAO,那么底层方法就会出现问题,因为JDBC连接未同步。

这可以通过让DAO实现一个简单地创建并返回新DAO的newInstance()方法来解决。

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();}
}

存储库可以使用存储库中的DAO作为存储库返回的DAO的工厂(在这种情况下我将重命名为Factory),如下所示:

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

<强>更新

至于您的问题,您的网络服务应该实现工厂还是可以使用您描述的存储库?答案再次取决于细节:

  • 对于网络服务,这是正常的 期待多个并发客户端
  • 因此执行的实例 两个客户的流程绝对不能 影响彼此
  • 这意味着他们必须没有共享状态
  • 工厂提供新的实例 每个请求,所以没有共享状态 当您使用工厂模式时
  • 如果(且仅当)您的实例 存储库是无国籍的 网络服务也可以使用 为此描述的存储库 他们可能需要实例化 实际执行的其他对象 基于请求的过程 参数传递

答案 2 :(得分:0)

如果您需要在创建内容时将多个维度分开,那么抽象工厂非常有用。

在窗口系统的常见示例中,您希望为各种窗口系统创建一系列窗口小部件,并为每个窗口系统创建一个具体工厂,以创建在该系统中工作的窗口小部件。

在构建DAO的情况下,如果您需要为域中的各种实体创建一个DAO系列,并希望创建整个系列的“sql”版本和“访问”版本,则可能很有用。 。这是我认为你的同学正在努力做的事情,如果这就是你正在做的事情,这可能是一个好主意。

如果你只有一件事变化,那就太过分了。