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

时间:2013-09-17 20:47:07

标签: design-patterns factory-pattern

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

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

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

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

我的问题是,我一直在使用共享方法的工厂(不是正式的模式)。但是,我正在寻找工厂方法并使用它,但我无法理解的是我如何确定抽象工厂类的哪个子类用于创建我的产品。根据我目前的理解,您仍然使用 new 关键字为声明为抽象工厂类的变量分配一个具体类。

例如:

Dim factory1 As IFactory = New ConcreteFactory1

Dim factory2 As IFactory = New ConcreteFactory2

如果我想根据数据库记录动态确定我想要返回哪个IFactory,我该怎么做?我最好不要使用工厂模式离开代码而不打扰工厂方法模式?我想避免在客户端代码中执行 select case if 语句。我可以将工厂方法模式包装在工厂模式中吗?

希望我有道理

1 个答案:

答案 0 :(得分:1)

嗯,这完全取决于您将使用的语言,以支持设计的想法。我将用Java描述这个想法,让我们开始。

您有以下内容:

AbstractFacotry instance1 = new ConcreteFacotry1();
AbstractFacotry instance2 = new ConcreteFacotry2();

您希望避免使用 ConcretFactory#。这就是为什么你将使用一个Factory类,它负责根据参数(在你的情况下,你提到的那个数据库记录)为你提供正确的 ConcretFactory#实例。我会尽量简短而又尽可能地解释,希望我不会在这个过程中失去任何人。

我将首先创建抽象类 AbstractFactory 以及为此示例扩展的具体类。

public abstract class AbstractFactory {}

当然你的内容会更详细,我只需要实例化它来运行几个测试。现在让我们很好地扩展它的类:

public class ConcreteFactory1 extends AbstractFactory {}

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

接下来是负责根据您的数据库参数为您提供AbstractFactory的具体实例的类。此实现假定数据库参数不超过15个。并且所述数据库参数也可以转换为String。

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

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

最后一件事是创建一个负责根据数据库参数调用正确方法的类。这是果汁所在的位置,以及避开 if-elses和开关的地方。这是您将从客户端拨打的课程。

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(..)负责根据dbParameter调用 FactoryInstantiator 中的相应方法。

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

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

}

这是打印输出:

class ConcreteFactory1
class ConcreteFactory2
class ConcreteFactory3
class ConcreteFactory4

你有它。希望能帮助到你。