首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >确定使用工厂方法设计模式时要使用的工厂

确定使用工厂方法设计模式时要使用的工厂
EN

Stack Overflow用户
提问于 2013-09-17 20:47:07
回答 1查看 764关注 0票数 1

目前,我正在对工厂的设计模式进行一些研究,并列出了我对每一种模式的理解的简要描述。如果其中任何一个不正确,请纠正我。

工厂--简单而非官方的设计模式,通常是一个类,它有一个或多个方法(有时是静态的)接受一个参数来确定要返回的抽象类型的哪个子类。

2)工厂方法--正式表示一个模式,并使用抽象的工厂类。对于预期返回类型的每个产品,创建一个关联的工厂类,并实现或覆盖所需的方法。在客户端代码中,尽管变量被声明为抽象的工厂,但它是用具体的实现实例化的。

3)抽象工厂--通过各种相互关联或相互依赖的方法返回多个类型的对象的模式。

我的问题是,我一直在用共享方法使用工厂(不是正式的模式)。然而,我正在考虑如何获取工厂方法并使用这个方法,但我无法理解的是如何确定抽象的工厂类的哪个子类来创建我的产品。根据我到目前为止的理解,您仍然使用新关键字将一个具体的类分配给声明为抽象工厂类的变量。

例如:

Dim factory1 As IFactory = New ConcreteFactory1

Dim factory2 As IFactory = New ConcreteFactory2

例如,如果我想动态地确定我想根据数据库记录返回哪个IFactory,我该如何做呢?我最好还是使用Factory模式来保留代码,而不使用Factory方法模式呢?我希望避免在客户端代码中执行select case或if语句。我能把工厂方法模式包装成工厂模式吗?

希望我说得通

EN

回答 1

Stack Overflow用户

发布于 2013-11-22 12:50:13

这很大程度上取决于您将使用哪种语言来支持设计思想。我将用Java来描述这个想法,让我们开始。

你有以下几点:

代码语言:javascript
运行
复制
AbstractFacotry instance1 = new ConcreteFacotry1();
AbstractFacotry instance2 = new ConcreteFacotry2();

你想要避免把ConcretFactory#.这就是为什么您将使用一个工厂类,它负责根据参数(在您的例子中,您提到的数据库记录)为您提供正确的ConcretFactory#实例。我会尽量简短地解释,希望我不会在这个过程中失去任何人。

我将从创建抽象类AbstractFactory和从抽象类扩展到示例的具体类开始。

代码语言:javascript
运行
复制
public abstract class AbstractFactory {}

当然,您的测试会更详细,我只需要实例化它来运行几个测试。现在让我们来看看从它扩展出来的类:

代码语言:javascript
运行
复制
public class ConcreteFactory1 extends AbstractFactory {}

我不会粘贴其他代码,它们都是一样的。下面是我创建的类:ConcreteFactory1、ConcreteFactory2、ConcreteFactory3、ConcreteFactory4.

接下来是负责根据数据库参数为您提供具体实例AbstractFactory的类。这个实现假设数据库参数不会超过15个。也可以将所述数据库参数转换为字符串。

代码语言:javascript
运行
复制
public class FactoryInstantiator {
public AbstractFactory optionOne(){
    return new ConcreteFactory1();
}

public AbstractFactory optionTwo(){
    return new ConcreteFactory2();
}

public AbstractFactory optionThree(){
    return new ConcreteFactory3();
}

public AbstractFactory optionFour(){
    return new ConcreteFactory4();
}
}

显然,名称option#是数据库参数的字符串转换。

最后一件事是创建一个类,它负责根据数据库参数调用正确的方法。这里是果汁的所在,也是避免if-else和开关的地方。这是您将从客户端调用的类。

代码语言:javascript
运行
复制
public class FactoryHandler {

public AbstractFactory getInstance(String databaseParameter) {
    try {
        return  getConcreteInstance(FactoryInstantiator.class, databaseParameter);
    } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | 
             InvocationTargetException | NoSuchMethodException ex) {
        Logger.getLogger(FactoryHandler.class.getName()).log(Level.SEVERE, null, ex);
    }
    throw new RuntimeException("Could not determine concrete instance based on data base parameter");
}


private AbstractFactory getConcreteInstance(Class<FactoryInstantiator> factoryInstantiator, String databaseParameter) 
                    throws InstantiationException, IllegalAccessException, IllegalArgumentException, 
                    InvocationTargetException, NoSuchMethodException {    
    Class[] methodParameterTypes=null;
    Object instance = factoryInstantiator.newInstance();
    Method method = factoryInstantiator.getDeclaredMethod(databaseParameter, methodParameterTypes);
    return  (AbstractFactory) method.invoke(instance);
}

}

具体来说,您将调用getInstance(...)方法来获取具体实例。此方法负责捕获调用getConcreteInstance(..).时可能出现的异常。这种分离是为了可读性和清晰性。

真正的交易是由getConcreteInstance(..)负责在FactoryInstantiator中调用基于dbParameter的适当方法。

让我们在主类中使用它,如下所示:

代码语言:javascript
运行
复制
public class Main {

public static void main(String[] args) {
    ArrayList<AbstractFactory> factories = new ArrayList<>();
    ArrayList<String> dbParameters = getDBparameters();
    FactoryHandler factoryHandler = new FactoryHandler();

    for(String dbParameter:dbParameters)
        factories.add( factoryHandler.getInstance(dbParameter) );

    for(AbstractFactory factory : factories)
        System.out.println(factory.getClass());

}

private static ArrayList<String> getDBparameters(){
    ArrayList<String> dbparameters = new ArrayList<>();
    dbparameters.add("optionOne");
    dbparameters.add("optionTwo");
    dbparameters.add("optionThree");
    dbparameters.add("optionFour");
    return dbparameters;
}

}

这是打印出来的:

代码语言:javascript
运行
复制
class ConcreteFactory1
class ConcreteFactory2
class ConcreteFactory3
class ConcreteFactory4

然后你就有了。希望能帮上忙。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18859590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档