抽象工厂设计模式的使用

3

我想学习创建型设计模式,现在我认为我已经理解了工厂方法模式。 但是当转向抽象工厂模式时,我无法找到它的用途。我知道我在这方面缺少些什么,但不知道具体是什么。

在抽象工厂模式中,我们将有一个抽象工厂,具体工厂将返回实例。假设我们正在处理汽车的创建。我们将拥有一个类似于以下代码的抽象工厂:

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)这本书吗? - Adam Arold
它旨在抽象化对象创建,例如客户端类希望在构造函数中获得一个CarFactory并使用它来创建汽车,客户端类不关心这是什么类型的汽车,也不应该知道。如果您读过GoF书籍,请再读一遍;p客户端类不应自己创建工厂。 - Łukasz
你可能想要查看这个问题。它包含了许多来自JDK的有用的GOF设计模式示例。 - Adam Arold
谢谢Lukasz,但我们是否可以在客户端类中有一个字符串值来表示汽车类型(“Audi”或“Volvo”)在它的构造函数中?就像工厂实例一样? - Jomy George
4个回答

5
对于您的例子,是的,工厂模式可以替代抽象工厂模式。
抽象工厂模式在需要创建同一系列不同产品但实际上并不知道该系列(例如沃尔沃或奥迪)时很有用。
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(); }
}

我相信你可以想象沃尔沃的同样情况。
现在假设我们有一个类来构建一辆汽车,它并不关心它是奥迪还是沃尔沃。
class CarBuilder {
    public static Car buildCar(ICarFactory factory) {
        Car car = factory.createCar();

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

        return car;
    }
}

现在我们的建造者类可以在不知道实际品牌的情况下工作,这使得建造者类符合开闭原则。如果未来出现第三个品牌,我们的建造者类仍然能够构建该汽车,而无需更改任何代码。由于抽象工厂,它是可扩展的但不可修改的。

2
在你的例子中:
  • 工厂方法模式是用于创建汽车的模式(隐藏了汽车创建的实现)

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

  • 因此,您可以认为:抽象工厂模式是创建工厂的工厂的模式

  • 这两种模式有不同的目的。

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


如何实例化抽象工厂与为什么需要它是两个不同的讨论话题。 - Kalpesh Soni

0

你已经非常理解工厂模式的使用:工厂允许你创建在编译时类型未知的对象(当然只是接口的子类)。现在,再往前迈一步:

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

这就是抽象工厂的用处:抽象工厂是一个工厂的工厂,它允许你创建在编译时类型未知的工厂:因此,你将会有

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

...然后您就可以实现EuropeanCarFactory、AmericanCarFactory等。


当你有一些带有构造函数参数的工厂类时,抽象工厂模式是非常有用的另一个例子:

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

通过动态实例化 (Class.forName("CarFactory").newInstance()) 创建一个 CarFactory 对象比较困难,因此再添加一层向上的分解是有用的:一个 抽象工厂,它决定如何实例化 CarFactory:

public interface AbstractCarFactory
{
    public CarFactory(boolean cheatingMotor);
}

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

注意:在常见应用程序中,抽象工厂模式足以适当地对应用程序的所有行为进行参数化。我从未听说过需要工厂的工厂的工厂的情况。

0

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

它为您生产Statement、CallableStatement等

在内部,它可以是OracleStatement或MySQLStatement

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

还请参见 设计模式:抽象工厂与工厂方法

关于您的原始代码

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

你要做的就是摆脱if-else 想想学习整个设计模式列表只是为了简单地摆脱你的代码中的if-else

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

事实是

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

要求客户端在每次调用时传递“Audi”是不合理的


即使我们使用工厂模式,我们也可以实现相同的效果。假设java.sql.Connection是一个接受代表“OracleStatement”或“MySQLStatement”的String的工厂模式,我看到了传递一些无效值的情况。 - Jomy George

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接