工厂方法模式与普通抽象 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实现吗?我们利用 TCPMessenger
和 UDPMessenger
共享的代码 - 对我来说,这不是一种模式,而是面向对象编程的核心特征,每个人从 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)
中的相同逻辑(TCPSocket
和 UDPSocket
),尤其是当我们可能想在以后添加更多 Socket
class 时。
这就是 工厂方法模式 发挥作用的地方,因为我们可以在抽象级别定义所有用于交换消息的通用行为,但保留 实际 Socket
实现(TCPSocket
和 UDPSocket
)的创建 到 Messenger
的子class(TCPMessenger
和 UDPMessenger
).
关于工厂方法模式替代方案的讨论
您可以将 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一个具体产品(TCPSocket
,UDPSocket
)并具有适用于 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
)
- 一篇摘要
Creator
class(Messenger
)
- 在
Creator
class (getSocket()
) 中定义的 Product factoryMethod()
方法
注意:Creator
和factoryMethod()
通常是抽象的,但是 Creator
可以定义一个默认值 Product
删除这个要求.
Creator
class 中的 operation()
方法使用由 factoryMethod()
编写的 ConcreteProduct
return(exchangeMessages(String)
)
- 至少一个
ConcreteCreator
class(TCPMessenger
和 UDPMessenger
))
这样
-
ConcreteCreator
classes 实现 Product factoryMethod()
创建和 return ConcreteProduct
- 抽象
Creator
class 通过所有 Product
实现的接口使用 ConcreteProduct
(return 由 Product factoryMethod()
编辑)
最后两点反映出Creator
对Product
接口有use依赖,ConcreteCreator
classes 具有 create 依赖关系及其对应的 ConcreteProduct
class.
再次注意,Client
class 不是模式本身的一部分(由 GoF 定义)。
总而言之,如果 TCPMessenger
和 UDPMessenger
class 实现 getSocket()
方法正确(我假设他们确实这样做了)。
我正在尝试了解工厂方法模式。我设法将它与 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实现吗?我们利用 TCPMessenger
和 UDPMessenger
共享的代码 - 对我来说,这不是一种模式,而是面向对象编程的核心特征,每个人从 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
.
工厂方法模式是一个简单的模式,但仍然是一个模式。
您的 Client
及其与工厂方法的关系
工厂方法模式的四人帮 (GoF) 定义并未具体提及 Client
作为模式本身的参与者。实际上,Client
最有可能通过其他操作间接使用工厂方法。
在您的情况下,Client
不关心正在使用的 Socket
,而只关心 Messenger
本身。但是,Messenger
依赖于 Socket
,因为它有一些使用 Socket
对象的行为。
因此,虽然 Client
本身不关心 Socket
,但它确实关心具有 use 依赖关系的 Messenger
Socket
.
由于 Socket
本身是抽象的,这给我们带来了问题,因为我们不想针对 Socket
的不同实现多次复制 exchangeMessages(String)
中的相同逻辑(TCPSocket
和 UDPSocket
),尤其是当我们可能想在以后添加更多 Socket
class 时。
这就是 工厂方法模式 发挥作用的地方,因为我们可以在抽象级别定义所有用于交换消息的通用行为,但保留 实际 Socket
实现(TCPSocket
和 UDPSocket
)的创建 到 Messenger
的子class(TCPMessenger
和 UDPMessenger
).
关于工厂方法模式替代方案的讨论
您可以将 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一个具体产品(TCPSocket
,UDPSocket
)并具有适用于 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
)- 一篇摘要
Creator
class(Messenger
) - 在
Creator
class (getSocket()
) 中定义的
Product factoryMethod()
方法
注意:Creator
和factoryMethod()
通常是抽象的,但是 Creator
可以定义一个默认值 Product
删除这个要求.
operation()
方法使用由factoryMethod()
编写的ConcreteProduct
return(exchangeMessages(String)
)- 至少一个
ConcreteCreator
class(TCPMessenger
和UDPMessenger
))
Creator
class 中的 这样
-
ConcreteCreator
classes 实现Product factoryMethod()
创建和 returnConcreteProduct
- 抽象
Creator
class 通过所有Product
实现的接口使用ConcreteProduct
(return 由Product factoryMethod()
编辑)
最后两点反映出Creator
对Product
接口有use依赖,ConcreteCreator
classes 具有 create 依赖关系及其对应的 ConcreteProduct
class.
再次注意,Client
class 不是模式本身的一部分(由 GoF 定义)。
总而言之,如果 TCPMessenger
和 UDPMessenger
class 实现 getSocket()
方法正确(我假设他们确实这样做了)。