工厂方法:"Patterns in Java" by Mark Grand vs GoF 解读

Factory Method: "Patterns in Java" by Mark Grand vs GoF interpretation

我正在通过“Java 中的模式”学习 Java 设计模式,Mark Grand 的第 1 卷(特别是工厂方法)。我的观点是为我自己强调最接近的模式之间的差异。有很好的答案阐明了工厂方法和抽象工厂之间的区别(Design Patterns: Factory vs Factory method vs Abstract Factory, What is the basic difference between the Factory and Abstract Factory Design Patterns?)。但我注意到,与我在“Java 中的模式”中读到的相比,大多数作者对工厂方法的解释有所不同。答案的解释更接近GoF书中的工厂方法。

GoF解读:

Grand的解读:

具体来说,我将描述我认为 Grand 和 GoF 解释之间的关键区别。 GoF 解释中多态性的来源是继承:Creator 的不同实现创建不同类型的 Product。 Mark Grand 解释中多态性的来源显然是“数据驱动 class 确定”(书中的例子):

Image createImage(String ext){
    if (ext.equals("gif"))
        return new GIFImage();
    if (ext.equals("jpeg"))
        return new JPEGImage();
    ...
}

CreationRequester 将对象创建委托给封装“数据驱动 class 确定”逻辑的其他对象,以通过 discriminator 参数选择正确类型的 ProductIF

谁能解释一下:

  1. Grand的工厂方法解释等同于GoF的工厂方法吗?它实际上是工厂方法吗?可能是 GoF 工厂方法的某种概括或特例?考虑到 UML class 图,我看不到这些解释之间的直接映射。
  2. 现在让我们考虑一下 GoF 解释。是否可以像 Mark Grand 描述的那样在单独的接口中定义工厂方法(而不是抽象 class)?还会是工厂方法吗?是否可以将 GoF 解释中的工厂方法视为 模板方法 的一种特例,即 returns 某些产品?
  3. 如果我们按照 Grand 描述的那样考虑工厂方法,那么很明显,工厂方法只是生产单一产品的抽象工厂的一个特例。我说得对吗?
  4. 如果只是把一个“数据驱动class判断”的逻辑封装成一个单独的class,这样的结构能叫“工厂方法”吗?

问题 #1。

  1. 没有
  2. 没有
  3. 有时 UML 使事情变得模糊多于它使事情变得清晰。

问题 #2。

  1. 我在大图里只看到一个工厂界面。我没有看到单独的界面。
  2. ?
  3. 是的。没有。

问题 #3。 号

问题 #4。 号


我不像以前那样熟悉我的 GoF 模式,但我会试一试。 我认为您对差异的看法是正确的。 GoF 模式使用继承实现多态,Grand 的示例使用条件逻辑实现多态。

操作上的区别在于,要在 Grand 的示例中添加一个新类型,我会修改方法 createImage:

if (ext.equals("png"))
       return new PngImage()

在 GoF 版本中,没有修改现有代码。我创建了一个名为 PngCreator 的新子 class,它实现了 Creator 接口。这是 open/closed 原则的一个很好的例子——GoF 工厂不允许修改,但模式对扩展开放(通过添加工厂接口的新实现)。

工厂与模板

Factory Method is always implemented using the Template Method patternAlpert、Brown 和 Woolf 的设计模式 Smalltalk Companion

是的,工厂方法模式是一种模板方法模式。然而,(GoF) 模式不仅仅是它的结构或图表。 GoF 书中的每个模式都包括 intent, motivation, applicability, participants,依此类推。意图和动机是使 Factory 和 Template 不同的部分原因。对于初学者来说,一个是创造模式,一个是行为模式。

工厂方法模式的目的是让工厂的子class决定实例化什么class。在 Grand 的版本中,我只看到一个具体的工厂,它使用条件逻辑。恕我直言,这与使用多个具体的 subclasses 不同。话又说回来,Grand 的版本确实将创建请求者与 class 名称分离。如果您将工厂修改为 return Jpeg2000 的实例而不是 Jpeg,编译器将不会报错。 CreationRequester 仅依赖于接口 Image。如果我正在使用别人的库并且我无法修改它,这很重要。如果避免创建请求者的重新编译是动机,那么 Grand 的版本可以正常工作。

Grand 的工厂方法模式是抽象工厂模式的特例吗?

我不这么认为。我将从我的(古老的)Design Patterns Smalltalk Companion 副本中借用示例。假设我的应用程序使用车辆。我可能有一个 VehicleFactory 接口,其中包含 'createTruck'、'createPassengerCar'、'createMotorcyle` 等方法。

车辆制造商对我的申请有何重要意义?进入抽象工厂模式! VehicleFactory 定义方法 createTruckcreatePassengerCarcreateMotorcyle。我创建了名为 ToyotaFactoryFordFactoryHondaFactory 的 classes,它们都实现了接口。

这里是每个具体的工厂return:

ToyotaFactory.createPassengerCar -> 凯美瑞

HondaFactory.createPassengerCar -> 雅阁

FordFactory.createPassengerCar -> 金牛座


ToyotaFactory.createMotorcycle -> FM6

HondaFactory.createMotorcycle -> 金翼

FordFactory.createPassengerCar -> return null 或抛出异常,或 ...

第二天,我加一个FiatFactory。因为客户端 classes 依赖于 VehicleFactory 接口,所以我不需要更改任何旧代码或重新编译任何东西。

  1. GoF 工厂方法模式定义了三种类型:Grand 的鉴别器 表示 GoF 所指的参数化工厂方法.
    • GoF 对单词 interface 的用法等同于 abstraction。它早于 Java 接口 class 和关键字的发明。接口和抽象 classes 是可以互换的。
    • 工厂方法是模板方法的特例:What are the differences between Abstract Factory and Factory design patterns?
  2. 否:Design Patterns: Abstract Factory vs Factory Method
  3. 否:没有继承和模板方法,这就是 Head First Design Patterns 所说的简单工厂。