什么时候使用抽象工厂模式?

发布于 2024-08-30 04:28:28 字数 3583 浏览 4 评论 0原文

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

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

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 类的属性文件

)。也就是说,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 是否需要使用 Abstract工厂?

I want to know when we need to use the abstract factory pattern.

Here is an example,I want to know if it is necessary.

The UML

THe above is the abstract factory pattern, it is recommended by my classmate.
THe following is myown implemention. I do not think it is necessary to use the pattern.

And the following is some core codes:

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

And the content of the Test.properties is just one line:

dao=net.SqlDao,net.SqlDao

So any ont can tell me if this suitation is necessary?


-------------------The following is added to explain the real suitation--------------

I use the example of Dao is beacuse it is common,anyone know it.

In fact,what I am working now is not related to the DAO,I am working to build a Web

service,the web serivce contains some algorithms to chang a file to other format,

For example:net.CreatePDF,net.CreateWord and etc,it expose two interfaces to client:getAlgorithms and doProcess.

The getAlogrithoms will return all the algorithms's ids,each id is realted to the
corresponding algorithm.

User who call the doProcess method will also provide the algorithm id he wanted.

All the algorithm extends the AbstractAlgorithm which define a run() method.

I use a AlogrithmsRepository to store all the algorithms(from

the properties file which config the concrete java classes of the algorithms by the web

service admin).That's to say, the interface DoProcess exposed by the web service is

executed by the concrete alogrithm.

I can give a simple example:
1)user send getAlgorithms request:

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

Then user will get a list of algorithms embeded in a xml.

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

2)user send a DoProcess to server by:

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

when the server recieve this type of requst,it will get the concrete algorithm instance according to the "algorithm" parameter(it is pdf in this request) from the AlgorithmRepostory. And call the method:

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

Then a pdf file will be sent to user.

BTW,in this example, the each algorithm is similar to the sqlDao,AccessDao.
Here is the image:

The design image

Now,does the AlgorithmRepostory need to use the Abstract Factory?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

靖瑶 2024-09-06 04:28:28

两种方法之间的主要区别在于,顶部方法使用不同的 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 的工厂(在这种情况下我将其重命名为 Factory),如下所示:

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

更新

至于您的问题,您的 Web 服务是否应该实现一个工厂或者它可以像你描述的那样使用存储库吗?同样,答案取决于细节:

  • 对于网络服务,这是正常的
    期望有多个并发客户端
  • 因此执行的实例
    两个客户的流程不得
    互相影响
  • 这意味着他们不能共享状态
  • 工厂交付了一个新的实例
    每个请求,因此不会共享任何状态
    当您使用工厂模式时
  • 如果(且仅当)您的实例
    存储库是无状态的
    网络服务也可以使用
    如您所描述的存储库,为此
    他们可能需要实例化
    实际执行的其他对象
    根据请求进行处理
    传递的参数

The main difference between the two approaches is that the top one uses different DAO factories to create DAO's while the bottom one stores a set of DAO's and returns references to the DAO's in the repository.

The bottom approach has a problem if multiple threads need access to the same type of DAO concurently as JDBC connections are not synchronised.

This can be fixed by having the DAO implement a newInstance() method which simply creates and returns a new 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();}
}

The repository can use the DAO's in the repository as factories for the DAO's returned by the Repository (which I would rename to Factory in that case) like this:

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

Update

As for your question should your web-service implement a factory or can it use the repository like you described? Again the answer depends on the details:

  • For web-services it is normal to
    expect multiple concurrent clients
  • Therefore the instances executing the
    process for two clients must not
    influence eachother
  • Which means they must not have shared state
  • A factory delivers a fresh instance on
    every request, so no state is shared
    when you use a factory pattern
  • If (and only if) the instances in your
    repository are stateless your
    web-service can also use the
    repository as you describe, for this
    they probably need to instantiate
    other objects to actually execute the
    process based on the request
    parameters passed
绮筵 2024-09-06 04:28:28

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

  • 调用者需要在调用 getDAO() 时显式指定 DAO 的类型。相反,调用者不应该关心它所使用的 DAO 类型,只要 DAO 符合接口即可。第一个设计允许调用者简单地调用 createDAO() 并获取要使用的接口。这种方式对使用哪个 impl 的控制更加灵活,并且调用者没有这个责任,这提高了设计的整体一致性。

If you ask to compare 2 designs from UML, 2nd API on UML have following disadvantage:

  • caller needs to explicitly specify type of DAO in call to getDAO(). Instead, caller shouldn't care about type of DAO it works with, as long as DAO complies with interface. First design allows caller simply call createDAO() and get interface to work with. This way control of which impl to use is more flexible and caller don't have this responsibility, which improves overall coherence of design.
旧夏天 2024-09-06 04:28:28

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

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

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

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

Abstract Factory is useful if you need to separate multiple dimensions of choices in creating something.

In the common example case of windowing systems, you want to make a family of widgets for assorted windowing systems, and you create a concrete factory per windowing system which creates widgets that work in that system.

In your case of building DAOs, it is likely useful if you need to make a family of DAOs for the assorted entities in your domain, and want to make a "sql" version and an "access" version of the entire family. This is I think the point your classmate is trying to make, and if that's what you're doing it's likely to be a good idea.

If you have only one thing varying, it's overkill.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文