我试图理解工厂方法模式。我设法将它与简单工厂区别开来,但现在我不明白为什么它实际上被称为"模式"。请看下面的例子:
类图链接
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
,并且由于它我们:
让子类决定实例化哪个类
但它不仅仅是一个普通的抽象类实现吗?我们利用TCPMessenger
和UDPMessenger
共享的代码 - 对我来说,这不是一种模式,而是面向对象编程的核心特性,每个人都知道从OOP语言学习的开始! / p>
此外,我认为命名此创作非常令人困惑。我们实际上关心exchangeMessages
方法,因此Client
(使用我们"模式&#34的代码的一部分)甚至不知道Socket
类创建我们&# 39;所有关于。它更像是一种实现Messenger
功能性(可以轻松扩展等等)的方法,而不是真正创造某种东西的方式。
我错过了这一点,还是我的例子无效?请伙计们,让我知道你对此有何看法。
提前致谢!
答案 0 :(得分:4)
对我来说,这不是一种模式,而是面向对象的核心功能 编程
大多数模式依赖于核心OOP功能:通过接口编程,覆盖,多态等等...
此外,我认为命名这个创作非常令人困惑。 我们实际上关心的是exchangeMessages方法,所以客户端(部分是 使用我们的"模式")的代码甚至不知道Socket类 我们所创造的创造。它更像是一种实施方式 Messenger功能(可以轻松扩展等...)比 真正创造某种东西的方法。
这取决于你所采取的观点
对于Messenger
抽象类的子类,例如TcpManager
,它们的父类定义除了这个工厂方法之外的所有方法,它们必须指定Socket getSocket();
应返回的内容。
因此,对于子类的观点,谈论Socket getSocket()
的创建模式是有道理的。
对于Messenger
的客户类,事情确实不同
客户甚至可能不需要直接使用这种方法
对于这些类,重要的是确实有办法漠不关心地操纵Messenger
的任何子类。
答案 1 :(得分:2)
Factory Method模式是一个简单的模式,但仍然是一种模式。
您的Client
及其与工厂方法的关系
工厂方法模式的四人帮(GoF)定义没有特别提到Client
作为模式本身的参与者。实际上,Client
最有可能通过其他操作间接使用工厂方法。
在您的情况下,Client
并不关心正在使用的Socket
,而只关心Messenger
本身。但是,Messenger
依赖于Socket
,因为它有一些使用Socket
对象的行为。
虽然Client
本身并不关心Socket
,但它确实关心Messenger
与Socket
的使用依赖关系}。
由于Socket
本身是抽象的,它给我们带来了一个问题,因为我们不想在exchangeMessages(String)
多次为Socket
的不同实现复制相同的逻辑(TCPSocket
和UDPSocket
),特别是当我们可能希望在以后添加更多Socket
课程时。
这是 Factory Method模式的用武之地,因为我们可以定义在抽象级别交换消息的所有通用行为,但保留创建实际Socket
实施(TCPSocket
和UDPSocket
)到Messenger
(TCPMessenger
和UDPMessenger
)的子类。
讨论工厂方法模式的替代方案
您可以将Socket
设置为Messenger
的字段,并使用策略模式方法将其注入,或者使用一个Socket
的构造函数作为参数。这种方法的一个缺点是我们必须保持对这个Socket
对象的引用作为类字段以预期它的使用。
但是,使用工厂方法模式,Socket
只会在需要时在方法exchangeMessages()
中创建,然后在方法终止时被丢弃,这可能会带来一些好处。这是以每次调用Socket
时必须创建一个exchangeMessages()
对象为代价的,这可能并不理想。
您还可以将所需的Socket
传递给要使用的exchangeMessages()
方法,但从长远来看,这可能不方便该方法的用户。
如果您的Messenger
子类也有一些不适用于所有类型Messenger
的特定行为(新方法/重写实现),那么Factory Method肯定是要走的路,因为我们需要子类化无论如何Messenger
,它允许我们严格执行工厂方法Socket
创建的getSocket()
类型。
也许其他人可以为工厂方法的优缺点做出贡献(特别是在Java中,因为这是问题的语言标签),我可以在适当的时候更新这个答案。
您的示例的有效性
关于您的示例是否无效。我认为首先完全理解模式和重要的类,操作和关系是有帮助的,以便符合工厂方法模式(由GoF指定)。
工厂方法模式允许您在抽象 Creator 类(在您的情况下为Messenger
)中定义操作(或可能是多个操作)使用一些对象(产品 [Socket
]),而不事先知道具体的产品并推迟其创建(因此术语创建模式)到工厂方法。
工厂方法本身(getSocket()
)在 Creator 类中是抽象的,将由 Concrete Creators 实现({ {1}},TCPMessenger
)所以多态性用于实现对象创建。
工厂方法将返回具体产品(UDPMessenger
,TCPSocket
)并具有适用于所有 Concrete的返回类型操作在抽象 Creator 类中使用的产品类(UDPSocket
)。
使用工厂方法的操作(Socket
)将使用<返回的 Concrete Product 接口产品的em>工厂方法,适用于所有 Concrete Product 类(exchangeMessages(String)
)。
结果是这种模式允许通过实现/子类化 Product 接口/类(或其子类......)并引入新的 Concrete Product 类来添加一个新的 Concrete Creator ,它从工厂方法返回新添加的具体产品,无需重新编写操作( s)使用此产品。
这意味着我们在引入新的 Concrete Products (开放/封闭原则)时不需要修改现有代码。
工厂方法模式的广义UML
关于UML的一些注释:
Socket
中为factoryMethod()
提供默认实现(即返回默认Creator
),从而允许Product
为非抽象Creator
可以是factoryMethod()
,但这对于模式的意图来说是肤浅的,因为public
主要用于factoryMethod()
operation()
不一定是抽象类,它可以是一个接口,也可以是一个具体的类您的示例的有效性(续)
在参考UML(和你的例子)时,模式的重要部分用不太冗长的术语表示如下:
必须存在
Product
接口(不一定是Java术语中的接口,实际上可以是类或抽象类)(在您的情况下为Product
)Socket
界面的{li> ConcreteProduct
个类(Product
,TCPSocket
)
UDPSocket
班级(Creator
)Messenger
类(Product factoryMethod()
)Creator
方法
注意 : getSocket()
和 Creator
通常是摘要,但 factoryMethod()
可以定义默认 Creator
删除此要求。
Product
(operation()
)返回的Creator
的{{1}}类中的ConcreteProduct
个方法
factoryMethod()
班级(exchangeMessages(String)
和ConcreteCreator
))这样
TCPMessenger
类实施UDPMessenger
来创建并返回ConcreteCreator
Product factoryMethod()
类通过所有ConcreteProduct
实现的接口使用Creator
(由ConcreteProduct
返回)最后两点反映Product factoryMethod()
与Product
接口有 use 依赖关系,而Creator
类有创建依赖于其对应的Product
类。
再次注意,ConcreteCreator
类不是模式本身的一部分(由GoF定义)。
总而言之,如果ConcreteProduct
和Client
类正确实现TCPMessenger
方法,那么您的示例将显示为上述要求的工厂方法。假设他们确实这样做了。