1

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

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

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

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

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

例如:

Dim factory1 As IFactory = New ConcreteFactory1

Dim factory2 As IFactory = New ConcreteFactory2

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

希望我说得通

4

1 回答 1

1

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

您有以下内容:

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

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

为了示例的目的,我将从创建抽象类AbstractFactory和从它扩展的具体类开始。

public abstract class AbstractFactory {}

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

public class ConcreteFactory1 extends AbstractFactory {}

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

接下来是负责根据您的数据库参数为您提供 AbstractFactory 的具体实例的类。此实现假定不会有超过 15 个左右的数据库参数。并且还可以将所述数据库参数转换为字符串。

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

显然 name option#是您的数据库参数的字符串翻译。

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

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

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

于 2013-11-22T12:50:13.560 回答