工厂方法模式与普通抽象 class 实现

Factory Method pattern vs ordinary abstract class implementation

我正在尝试了解工厂方法模式。我设法将它与 Simple Factory 区分开来,但现在我不明白为什么它实际上被称为 "pattern"。请看我下面的例子:

Class 图link

Messenger 的示例 java 代码:

public String exchangeMessages(String messageToSend) {
   Socket socket = getSocket();
   socket.open();
   socket.send(messageToSend);
   String receivedMessage = socket.receive();
   socket.close();
   return receivedMessage;
}

对于客户

public static void main(String[] args) {
   Messenger messenger = new TCPMessenger("127.0.0.1", 4321);
   String result = messenger.exchangeMessages("Hello!");
   System.out.println(result);
}

如果我没理解错的话,一切都是有道理的,因为 exchangeMessages 方法存在。我们在其中使用抽象 工厂方法 getSocket 并感谢它我们:

let subclasses decide which class to instantiate

但这不就是一个普通的抽象class实现吗?我们利用 TCPMessengerUDPMessenger 共享的代码 - 对我来说,这不是一种模式,而是面向对象编程的核心特征,每个人从 OOP 语言学习的开始就知道!

此外,我认为命名这个 creational 非常混乱。我们实际上关心 exchangeMessages 方法,所以 Client (使用我们的 "pattern" 的部分代码)甚至不知道 Socket class 我们创建了哪个都是关于。它更像是一种实现 Messenger 功能(可以轻松扩展等...)的方式,而不是一种真正创造某些东西的方式。

我是不是没抓住要点,还是我的例子无效?请伙计们,让我知道你对此有何看法。

提前致谢!

for me, this is not a pattern but a core feature of Object-Oriented Programming

大多数模式都依赖于核心 OOP 功能:通过接口编程、重写、多态性等等...

Moreover, I think that naming this creational is very confusing. We actually care about exchangeMessages method, so Client (part of the code that uses our "pattern") is not even aware of the Socket class which creation we're all about. It's more like a way to implement Messenger functionality (which can be easily extended etc...) than a way to really create something.

这取决于你的观点。
对于 Messenger 抽象 class 的子 class,例如 TcpManager,它们的父 class 定义了除此工厂方法之外的所有方法,它们必须实现以指定什么Socket getSocket(); 应该 return.
因此,对于 subclasses 的观点,谈论 Socket getSocket() 的创作模式是有道理的。

对于 Messenger 的 class 个客户,情况确实不同。
客户甚至可能不需要直接使用此方法。
对于这些 classes,重要的是确实有一种方法可以无差别地操作 Messenger.

的任何子 class

工厂方法模式是一个简单的模式,但仍然是一个模式。

您的 Client 及其与工厂方法的关系

工厂方法模式的四人帮 (GoF) 定义并未具体提及 Client 作为模式本身的参与者。实际上,Client 最有可能通过其他操作间接使用工厂方法。

在您的情况下,Client 不关心正在使用的 Socket,而只关心 Messenger 本身。但是,Messenger 依赖于 Socket,因为它有一些使用 Socket 对象的行为。

因此,虽然 Client 本身不关心 Socket,但它确实关心具有 use 依赖关系的 Messenger Socket.

由于 Socket 本身是抽象的,这给我们带来了问题,因为我们不想针对 Socket 的不同实现多次复制 exchangeMessages(String) 中的相同逻辑(TCPSocketUDPSocket),尤其是当我们可能想在以后添加更多 Socket class 时。

这就是 工厂方法模式 发挥作用的地方,因为我们可以在抽象级别定义所有用于交换消息的通用行为,但保留 实际 Socket 实现(TCPSocketUDPSocket)的创建Messenger 的子class(TCPMessengerUDPMessenger).


关于工厂方法模式替代方案的讨论

您可以将 Socket 设置为 Messenger 的字段,然后使用 策略模式 方法注入它,或者使用一个构造函数Socket 作为参数。这种方法的一个缺点是我们必须将此 Socket 对象的引用作为一个 class 字段来维护,以期待它的使用。

然而,使用工厂方法模式,Socket 只会在需要时在方法 exchangeMessages() 中创建,然后在方法终止时丢弃,这可能会有一些好处。这是以每次调用 exchangeMessages() 时必须创建 Socket 对象之一为代价的,这可能并不理想。

你也可以将需要的Socket传递给exchangeMessages()方法来使用,但从长远来看,这对方法的使用者来说可能不太方便。

如果你的 Messenger subclasses 也有一些特定的行为(新方法/覆盖实现)不适用于所有类型的 Messenger,那么工厂方法肯定是方式去,因为我们需要 subclass Messenger 并且它允许我们严格执行由工厂方法 getSocket().

创建的 Socket 的类型

也许其他人可以为工厂方法的 pros/cons 做出贡献(特别是在 Java 中,因为这是问题的语言标记),我可以在适当的时候更新这个答案。


你的例子的有效性

关于你的例子是否无效。我认为首先完全理解模式和重要的 classes、操作和关系以符合工厂方法模式(由 GoF 指定)是有帮助的。

工厂方法模式允许您在抽象 Creator class 中定义一个 Operation(或可能的几个操作) (在你的情况下 Messenger)将使用一些对象(Product [Socket])而不知道具体的 Product 并将其创建(因此术语 创建模式)推迟到 工厂方法

工厂方法本身(getSocket())在Creatorclass中是抽象的,将被实现by Concrete Creators (TCPMessenger, UDPMessenger) 所以使用多态来实现Object的创建。

工厂方法将return一个具体产品TCPSocketUDPSocket)并具有适用于 Operation 使用的所有 Concrete Product classes (Socket) 的 return 类型] 摘要 Creator class.

使用工厂方法操作 (exchangeMessages(String))将使用具体的 Product return 由 Factory Method 接口 Product 编辑,适用于所有 混凝土产品 classes (Socket).

结果是这个模式允许新的具体产品class通过实现/subclass添加 Product 接口/class(或其子classes...)并引入新的Concrete Creator,其中returns新添加的 Concrete Product 来自其 Factory Method,从而无需重写您的 Operation(s) 使用此 Product.

这意味着我们在引入新的具体产品时不需要修改现有代码(Open/Closed原则)。


工厂方法模式的通用 UML

关于 UML 的一些注释:

  • factoryMethod() 可以在 Creator 中给出默认实现(即默认 Product 到 return),进而允许 Creator非抽象
  • 如果需要,factoryMethod() 可以是 public,但这对模式的意图来说是肤浅的,因为 factoryMethod() 主要供 operation() 使用
  • Product不一定是抽象的class,可以是接口也可以是具体的class

示例的有效性(续)

参考 UML(和您的示例),该模式的重要部分用不太冗长的术语如下:

一定存在

  • 一个Product接口(不一定是Java术语中的接口,在现实中可能是class或抽象class)(在你的情况下 Socket
  • ConcreteProduct classes 实现了 Product 接口 (TCPSocket, UDPSocket)
  • 一篇摘要Creatorclass(Messenger)
  • Creator class (getSocket())
  • 中定义的 Product factoryMethod() 方法

注意CreatorfactoryMethod()通常是抽象的,但是 Creator 可以定义一个默认值 Product 删除这个要求.

    Creatorclass 中的
  • operation() 方法使用由 factoryMethod() 编写的 ConcreteProduct return(exchangeMessages(String) )
  • 至少一个 ConcreteCreator class(TCPMessengerUDPMessenger))

这样

  • ConcreteCreator classes 实现 Product factoryMethod() 创建和 return ConcreteProduct
  • 抽象 Creator class 通过所有 Product 实现的接口使用 ConcreteProduct(return 由 Product factoryMethod() 编辑)

最后两点反映出CreatorProduct接口有use依赖,ConcreteCreatorclasses 具有 create 依赖关系及其对应的 ConcreteProduct class.

再次注意,Client class 不是模式本身的一部分(由 GoF 定义)。

总而言之,如果 TCPMessengerUDPMessenger class 实现 getSocket() 方法正确(我假设他们确实这样做了)。