【问题标题】:Abstract Factory Design Pattern use抽象工厂设计模式的使用
【发布时间】:2015-10-01 14:52:17
【问题描述】:

我正在尝试学习创造设计模式,我想我现在了解工厂方法模式。 但是在转向抽象工厂模式时,我找不到它的用途。我知道我错过了一些东西,但不知道在哪里。

在抽象工厂模式中,我们将有一个抽象工厂,而具体工厂将返回实例。假设我们正在处理 Cars 的创建。我们将拥有一个像

这样的抽象工厂
public interface CarFactory{
    public Car getCar();
}

我们的具体工厂将类似于

public class AudiFactory{
    public Car getCar(){
        return new Audi();
    }
}

public class VolvoFactory{
    public Car getCar(){
        return new Volvo();
    }
}

在用户类中我们会像这样使用它

CarFactory factory = new AudiFactory();
Car carAudi = factory.getCar();
factory = new VolvoFactory();
Car carVolvo = factory.getCar();

我认为我们也可以使用工厂模式构建相同的功能

public class CarFactory{

    public Car getCar(String make){
    if("Audi".equals(make))
        return new Audi();
    else if("Volvo".equals(make))
        return new Volvo();
    }
}

在用户类中我们可以

CarFactory factory = new CarFactory();
Car carAudi = factory.getCar("Audi");
Car carVolvo = factory.getCar("Volvo");

如果我的理解是正确的(如果有错误请纠正我),为什么我们需要另一种设计模式呢?

【问题讨论】:

  • 你读过GoF的设计模式书吗?
  • 它是为了抽象对象的创建,例如一个客户端类期望得到一个CarFactory给构造函数并用它来创建汽车,客户端类不关心它是什么类型的汽车并且它不应该知道。如果你读过 GoF 的书,可能会再读一遍;p 客户端类不应该自己创建工厂。
  • 您可能需要检查this 问题。它有很多来自 JDK 的有用示例。
  • 感谢 Lukasz,但我们不能有一个客户端类,其构造函数中的字符串值表示汽车类型(“Audi 或“Volvo”)吗?就像 Factory 实例一样?

标签: java design-patterns abstract-factory


【解决方案1】:

对于您的示例,是的,您是对的,工厂模式可以替换抽象工厂模式。

当您需要创建同一家族的不同产品而不实际了解家族(沃尔沃或奥迪)时,抽象工厂是有意义的。

interface Car {}
interface Engine {}
interface Gear {}

interface ICarFactory {
    Car createCar();
    Engine createEngine();
    Gear createGear();
}

class AudiCar implements Car {}
class AudiEngine implements Engine {}
class AudiGear implements Gear {}

class AudiFactory implements ICarFactory {
    public Car createCar() { return new AudiCar(); }
    public Engine createEngine() { return new AudiEngine(); }
    public Gear createGear() { return new AudiGear(); }
}

我相信你可以为沃尔沃想象同样的东西。

现在假设我们有一个构建Car 的类,它不关心它是奥迪还是沃尔沃。

class CarBuilder {
    public static Car buildCar(ICarFactory factory) {
        Car car = factory.createCar();

        car.setEngine(factory.createEngine());
        car.setGear(factory.createGear());

        return car;
    }
}

现在我们的builder类可以在不知道实际品牌的情况下工作,这使得builder类符合Open/Closed Principle。如果将来有第三个品牌出现,我们的建造者阶级仍然能够建造那辆汽车,而无需更改单行代码。由于抽象工厂,它对扩展开放但对更改关闭..

【讨论】:

    【解决方案2】:

    在你的例子中:

    • Factory Method Pattern是创建汽车的模式(隐藏汽车创建的实现)

    • 抽象工厂模式是创建汽车工厂的模式(汽车工厂创建,非汽车创建,专注于工厂创建)

    • 所以你可以认为:抽象工厂模式是一种创建Factory of Factory的模式

    • 这两种模式有不同的用途。

    抽象工厂模式(使用接口/抽象实现)+IoC pattern -> 帮助您决定在运行时使用什么汽车工厂类型 - 不是在编译时(工厂方法模式不适合这种要求)

    【讨论】:

    • 抽象工厂是如何被实例化的,这与你为什么首先需要它是一个单独的讨论
    【解决方案3】:

    您已经很好地理解了工厂模式的使用:工厂允许您创建在编译时类型未知的对象(只是接口的子类)。现在,更进一步:

    现在你有一个CarFactory 来创建Car 对象。但是,当您的程序中同时需要多个工厂时,您将如何管理?

    这就是 抽象工厂 出现的时候:抽象工厂是一个工厂工厂,它允许您创建在编译时类型未知的工厂:所以,您会有

    public interface AbstractCarFactory
    {
        public CarFactory getCarFactory(String area);
    }
    

    ...您将能够实现 EuropeanCarFactory、AmericanCarFactory 等。


    抽象工厂有用的另一个例子是当你有一些工厂类在其构造函数中带有参数时:

    public CarFactory
    {
        public CarFactory(boolean cheatingMotor) {...}
    }
    

    通过动态实例化 (Class.forName("CarFactory").newInstance()) 很难创建一个 CarFactory 对象,因此向上一层分解很有用:一个决定如何实例化 CarFactory 的抽象工厂: p>

    public interface AbstractCarFactory
    {
        public CarFactory(boolean cheatingMotor);
    }
    
    public class MyAbstractCarFactory implements AbstractFactory
    {
        public CarFactory(boolean cheatingMotor)
        {
            return new CarFactory(true);
        }
    }
    

    注意:在普通应用程序中,抽象工厂模式足以正确参数化所有应用程序的行为。我从来不知道需要一个工厂的工厂的例子。

    【讨论】:

      【解决方案4】:

      想想 java.sql.Connection 对象 对我来说,它是一个抽象工厂

      它会为你生成 Statement、CallableStatement 等

      内部可以是 OracleStatement 或 MySQLStatement

      您的客户端代码是干净的,它不关心它如何在内部将套接字连接到数据库服务器

      另见 Design Patterns: Abstract Factory vs Factory Method

      关于你的原始代码

      想想现实世界,通用汽车不是在丰田“工厂”或一些通用汽车工厂生产的 :)

      你正在实现的是摆脱 if-else 考虑学习整个设计模式列表以简单地摆脱 r 代码中的 if-else

      如果 Sun 有一组有限的数据库要处理,他们可以编写一些如果没有的话

      事实是

      1) 不是sun写的SQL驱动 2) 使用这种模式,您可以在代码中“注入”任何驱动程序,而无需担心它是如何工作的,只需依赖接口

      要求客户在每次通话时都传递“Audi”是不合理的

      【讨论】:

      • 即使我们使用工厂模式,我们也可以达到同样的效果。如果 java.sql.Connection 是一个 FactoryPattern,它接受代表“OracleStatement”或“MySQLStatement”的字符串怎么办。我看到了传递一些无效值的情况。
      猜你喜欢
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多