抽象工厂:实现方式

Abstract factory: ways of realization

我现在正在学习设计模式并阅读每种模式的不同资源。我有一个关于模式抽象工厂的问题。我读到了两种实现这一点的方法。我在没有意识到的情况下使用这个工厂来写。例如,我制作了不同的门。

第一种方式。我们有通用的class门厂,它包括不同的方法来制作不同类型的门(return适合class的门):

$doorFactory = new DoorFactory();
$door1 = $doorFactory->createWoodDoor();

$doorFactory = new DoorFactory();
$door2 = $doorFactory->createSteelDoor();

第二种方式。我们有父级 class DoorFactory 和扩展 classes 用于 WoodDoorFactory 和 SteelDoorFactory。这个classes实现了相同的方法createDoor(和Door的return相应class)

$woodDoorFactory = new WoodDoorFactory();
$door1 = $woodDoorFactory->createDoor();

$steelDoorFactory = new SteelDoorFactory();
$door2 = $steelDoorFactory->createDoor();

您怎么看,哪种方式更优化和规范?

请想象一下当你的工厂被传递时的情况,客户端代码需要询问工厂的只是创建一扇门(不关心木头和钢材),你会明白为什么第二种方式更好。假设我们有一个 class Client 方法 foo 使用工厂(我正在使用 Java 但它应该很容易理解):

class Client {
    private DoorFactory factory;
    public Client(DoorFactory factory) { this.factory = factory; }
    public void foo() {
        Door door = factory.createDoor();
    }
}

现在您可以将 WoodDoorFactorySteelDoorFactoryWhateverDoorFactory 传递给 Client 的构造函数。

此外,更不用说您的第一种方式可能违反了 The Single Responsibility Principles,因为 DoorFactory class 知道很多可能无关的事情。实际上,它知道如何创建需要 Wood APIs 的木门(仅举个例子),它知道如何创建需要 Steel APIs 的钢门。这明显减少了在另一个不想依赖 Wood APIsSteel APIs 的环境中重用 DoorFactory class 的机会。你的第二种方式不会出现这个问题。

与其他答案一样,我在实践中也通常更喜欢第二种方法。我发现它是一种更灵活、更有用的依赖注入方法。

也就是说,我确实认为在某些情况下第一种方法即使不是更好也同样有效 - 它们只是不那么常见。我想到的一个例子是 XML 文档对象模型。如果你曾经使用过微软的c++XMLDOM文档API那么你就会熟悉这种方法(见https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms760218(v%3dvs.85)

在这种情况下,可以进入 XML 文档的定义明确的元素数量有限。也不需要能够动态扩展可以进入 XML 文档的元素类型——这都是由一些标准委员会预先确定的。因此,第一种工厂方法在这里适用,因为您可以预先确定您需要从一开始就能够创建的所有不同类型的东西。

在这种情况下,另一个优点是通过使 XML 文档 class 成为其中包含的所有元素的工厂,XML 文档已完成控制这些内部对象的生命周期。注意:它们不允许在多个 XML 文档实例中使用相同的子元素。如果您想使用来自一个 XML 文档的节点并将其放置在另一个 XML 文档中,您将需要通过第二个 XML 文档来生成一个新的节点元素作为任何和所有子元素的副本。

这种情况与 OP 中的示例的一个显着区别是,工厂方法不是用于提供创建同一类型事物的多种方法,这里的工厂知道如何创建一堆高度相关的(和连接的)对象类型。