据我估计,@TomDalling 给出的答案确实是正确的(就其价值而言),但是评论中似乎仍然存在很多混乱。
我在这里所做的是为这两种模式创建了一些稍微不典型的示例,并试图使它们乍一看非常相似。这将有助于查明将它们分开的关键差异。
如果您对这些模式完全陌生,那么这些示例可能不是最好的起点。
工厂方法
客户端.javaish
Client(Creator creator) {
ProductA a = creator.createProductA();
}
Creator.javaish
Creator() {}
void creatorStuff() {
ProductA a = createProductA();
a.doSomething();
ProductB b = createProductB();
b.doStuff();
}
abstract ProductA createProductA();
ProductB createProductB() {
return new ProductB1();
}
为什么有 aCreator
和 a Client
?
为什么不?两者FactoryMethod
都可以使用,但它的类型Creator
决定了创建的特定产品。
为什么没有createProductB
抽象在Creator
?
可以提供默认实现,子类仍然可以覆盖该方法以提供自己的实现。
我认为工厂方法只能创建一种产品?
每个方法确实只返回一个产品,但创建者可以使用多个工厂方法,它们不一定以任何特定方式相关。
抽象工厂
客户端.javaish
AbstractFactory factory;
Client() {
if (MONDAY) {
factory = new Factory2();
} else {
factory = new AbstractFactory();
}
}
void clientStuff() {
ProductA a = factory.createProductA();
a.doSomething();
ProductB b = factory.createProductB();
b.doStuff();
}
等待!你AbstractFactory
不是,嗯……呃摘要
没关系,我们仍然提供接口。create 方法的返回类型是我们想要制作的产品的超类型。
圣烟蝙蝠侠!Factory2
没有覆盖createProductA()
,“产品系列”发生了什么?
模式中没有任何内容表明一个对象不能属于多个系列(尽管您的用例可能会禁止它)。每个混凝土工厂负责决定允许一起创建哪些产品。
那不可能,Client
没有使用依赖注入
你必须决定你的具体类将在某个地方,Client
仍然写入AbstractFactory
接口。
这里的困惑是人们将组合与依赖注入混为一谈。不管它是如何得到的, Client
HAS-A 。AbstractFactory
对比IS-A关系,它们Client
之间AbstractFactory
没有继承关系。
主要差异
- 抽象工厂总是关于对象家族
- 工厂方法只是一种允许子类指定具体对象类型的方法
- 抽象工厂为客户端提供了一个接口,并且与使用产品的地方是分开的,工厂方法可以由创建者自己使用或暴露给客户端。
概括
工厂的目的是向客户或自身提供对象。
创建者有自己的职责,可能需要使用对象或将它们传递给客户端
定义一个用于创建对象的接口,但让子类决定要实例化哪个类。工厂方法允许类将实例化推迟到子类。- GoF
仅抽象工厂:
提供[s] 一个接口,用于创建相关或依赖对象的系列,而无需指定它们的具体类。- GoF
如果您想使用图表,请使用 PlantUML 代码:
@startuml FactoryMethod
abstract class Creator {
creatorStuff()
{abstract} createProductA(): ProductA
createProductB(): ProductB
}
class Creator1 {
createProductA(): ProductA
}
class Creator2 {
createProductA(): ProductA
createProductB(): ProductB
}
together {
interface ProductA {
doSomething()
}
class ProductA1
' class Product1B
}
together {
interface ProductB {
doStuff()
}
class ProductB1
class ProductB2
}
Client --> Creator
Creator <|-- Creator1
Creator <|-- Creator2
Creator --> ProductB1
ProductA1 <-- Creator1
ProductA1 <-- Creator2
ProductB2 <-- Creator2
ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2
ProductA <- Creator
@enduml
@startuml AbstractFactory
together {
interface ProductA {
doSomething()
}
class ProductA1
}
together {
interface ProductB {
doStuff()
}
class ProductB1
class ProductB2
}
class AbstractFactory {
createProductA(): ProductA
createProductB(): ProductB
--
-
}
class Factory2 {
createProductB(): ProductB
}
Client --> AbstractFactory
AbstractFactory <|-- Factory2
ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2
AbstractFactory --> ProductA1
AbstractFactory --> ProductB1
ProductB2 <-- Factory2
@enduml