Factory Method模式与普通抽象类实现

时间:2017-11-24 22:41:02

标签: java oop design-patterns factory-pattern

我试图理解工厂方法模式。我设法将它与简单工厂区别开来,但现在我不明白为什么它实际上被称为"模式"。请看下面的例子:

类图链接

enter image description here

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,并且由于它我们:

  

让子类决定实例化哪个类

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

此外,我认为命名此创作非常令人困惑。我们实际上关心exchangeMessages方法,因此Client(使用我们"模式&#34的代码的一部分)甚至不知道Socket类创建我们&# 39;所有关于。它更像是一种实现Messenger功能性(可以轻松扩展等等)的方法,而不是真正创造某种东西的方式。

我错过了这一点,还是我的例子无效?请伙计们,让我知道你对此有何看法。

提前致谢!

2 个答案:

答案 0 :(得分:4)

  

对我来说,这不是一种模式,而是面向对象的核心功能   编程

大多数模式依赖于核心OOP功能:通过接口编程,覆盖,多态等等...

  

此外,我认为命名这个创作非常令人困惑。   我们实际上关心的是exchangeMes​​sages方法,所以客户端(部分是   使用我们的"模式")的代码甚至不知道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,但它确实关心MessengerSocket使用依赖关系}。

由于Socket本身是抽象的,它给我们带来了一个问题,因为我们不想在exchangeMessages(String)多次为Socket的不同实现复制相同的逻辑(TCPSocketUDPSocket),特别是当我们可能希望在以后添加更多Socket课程时。

这是 Factory Method模式的用武之地,因为我们可以定义在抽象级别交换消息的所有通用行为,但保留创建实际Socket实施(TCPSocketUDPSocket)到MessengerTCPMessengerUDPMessenger)的子类。

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

您可以将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)所以多态性用于实现对象创建。

工厂方法将返回具体产品UDPMessengerTCPSocket)并具有适用于所有 Concrete的返回类型操作在抽象 Creator 类中使用的产品类(UDPSocket)。

使用工厂方法操作Socket)将使用<返回的 Concrete Product 接口产品的em>工厂方法,适用于所有 Concrete Product 类(exchangeMessages(String))。

结果是这种模式允许通过实现/子类化 Product 接口/类(或其子类......)并引入新的 Concrete Product 类来添加一个新的 Concrete Creator ,它从工厂方法返回新添加的具体产品,无需重新编写操作( s)使用此产品

这意味着我们在引入新的 Concrete Products (开放/封闭原则)时不需要修改现有代码。

工厂方法模式的广义UML

Factory Method Pattern

关于UML的一些注释:

  • 可以在Socket中为factoryMethod()提供默认实现(即返回默认Creator),从而允许Product为非抽象
  • 如果需要,Creator可以是factoryMethod(),但这对于模式的意图来说是肤浅的,因为public主要用于factoryMethod()
  • operation()不一定是抽象类,它可以是一个接口,也可以是一个具体的类

您的示例的有效性(续)

在参考UML(和你的例子)时,模式的重要部分用不太冗长的术语表示如下:

必须存在

  • Product接口(不一定是Java术语中的接口,实际上可以是类或抽象类)(在您的情况下为Product
  • 实现Socket界面的{li> ConcreteProduct个类(ProductTCPSocket
  • 抽象UDPSocket班级(Creator
  • Messenger类(Product factoryMethod()
  • 中定义的Creator方法

注意 getSocket() Creator 通常是摘要,但 factoryMethod() 可以定义默认 Creator 删除此要求

    使用Productoperation())返回的Creator的{​​{1}}类中的
  • ConcreteProduct个方法
  • 至少有一个factoryMethod()班级(exchangeMessages(String)ConcreteCreator))

这样

  • TCPMessenger类实施UDPMessenger来创建并返回ConcreteCreator
  • 抽象Product factoryMethod()类通过所有ConcreteProduct实现的接口使用Creator(由ConcreteProduct返回)

最后两点反映Product factoryMethod()Product接口有 use 依赖关系,而Creator类有创建依赖于其对应的Product类。

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

总而言之,如果ConcreteProductClient类正确实现TCPMessenger方法,那么您的示例将显示为上述要求的工厂方法。假设他们确实这样做了。