据我估计,@TomDalling给出的答案确实是正确的(不管它有什么价值),但是评论中似乎仍然有很多困惑。
我在这里所做的是为这两种模式创建一些略显非典型的示例,并试图使它们乍一看非常相似。这将有助于查明将它们分开的关键差异。
如果您对这些模式完全不熟悉,那么这些示例可能不是最好的开始。
工厂方法
Client.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();
}
为什么会有创造者和客户?
为什么不呢?FactoryMethod可以与两者一起使用,但它将是决定所创建的特定产品的Creator类型。
为什么createProductB在Creator中不是抽象的?
可以提供默认实现,子类仍然可以覆盖该方法以提供自己的实现。
我以为工厂方法只生产一种产品?
每个方法只返回一个产品,但创建者可以使用多个工厂方法,只是它们不一定以任何特定的方式相关。
抽象工厂
Client.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不是,嗯……er文摘
没关系,我们仍然在提供接口。create方法的返回类型是我们想要生成的产品的超类型。
圣烟蝙蝠侠!Factory2没有覆盖createProductA(),“产品族”发生了什么?
模式中并没有说一个对象不能属于一个以上的家族(尽管您的用例可能禁止这样做)。每个混凝土工厂负责决定哪些产品可以一起生产。
这是不对的,客户端没有使用依赖注入
您必须决定某个地方的具体类是什么,客户机仍然被写入AbstractFactory接口。
这里的混淆在于人们将组合与依赖注入混为一谈。客户端拥有一个AbstractFactory,而不管它是如何得到它的。与IS-A关系相比,Client和AbstractFactory之间没有继承关系。
关键的不同点
抽象工厂总是关于对象的家族
工厂方法只是一个允许子类指定具体对象类型的方法
抽象工厂为客户端提供了一个接口,它与产品的使用位置是分开的,工厂方法可以由创建者自己使用,也可以暴露给客户端。
总结
工厂的目的是为客户端或工厂本身提供对象。
创建者有自己的职责,可能需要使用对象或将对象传递给客户端
定义一个用于创建对象的接口,但是让子类来决定实例化哪个类。工厂方法允许类延迟实例化到子类。——GoF
抽象工厂:
提供一个接口来创建相关或依赖的对象族,而不指定它们的具体类。——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