5

我想知道我们什么时候需要使用抽象工厂模式。

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

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

所以任何ont可以告诉我这个西装是否有必要?


--------添加以下说明真正的适合--------------

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

其实我现在做的和DAO没有关系,我在做一个Web

服务,网络服务包含一些将文件更改为其他格式的算法,

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

getAlogrithoms 将返回所有算法的 id,每个 id 都对应于相应的算法。

调用 doProcess 方法的用户也会提供他想要的算法 id。

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

我使用 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

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

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

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

顺便说一句,在这个例子中,每个算法都类似于 sqlDao,AccessDao。这是图像:

设计形象

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

4

3 回答 3

2

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

  • 调用者需要在调用 getDAO() 时明确指定 DAO 的类型。相反,调用者不应该关心它使用的 DAO 类型,只要 DAO 符合接口。第一个设计允许调用者简单地调用 createDAO() 并获取接口来使用。这种方式控制使用哪个 impl 更灵活,调用者没有这个责任,这提高了设计的整体一致性。
于 2010-04-23T12:43:10.273 回答
2

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

如果多个线程需要同时访问相同类型的 DAO,因为 JDBC 连接不同步,则底层方法会出现问题。

这可以通过让 DAO 实现一个newInstance()简单地创建并返回一个新 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();}
}

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

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

更新

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

  • 对于 Web 服务,期望多个并发客户端是正常的
  • 因此,为两个客户端执行进程的实例不能相互影响
  • 这意味着它们不能共享状态
  • 工厂为每个请求提供一个新实例,因此当您使用工厂模式时不会共享任何状态
  • 如果(且仅当)您的存储库中的实例是无状态的,您的 Web 服务也可以使用您所描述的存储库,为此他们可能需要实例化其他对象以根据传递的请求参数实际执行该过程
于 2010-04-23T13:09:38.253 回答
0

如果您需要在创建某些东西时分离多个选择维度,则抽象工厂非常有用。

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

在您构建 DAO 的情况下,如果您需要为域中的各种实体创建一个 DAO 系列,并且想要制作整个系列的“sql”版本和“access”版本,这可能会很有用。这就是我认为你的同学想要表达的观点,如果你正在这样做,那可能是个好主意。

如果你只有一件事不同,那就太矫枉过正了。

于 2010-04-23T21:35:31.137 回答