关于设计模式中的“抽象工厂模式”与“工厂方法模式”,我浏览过网络上面的一些资料和文章,也拜读了GoF的《设计模式》,发现部分网络上的内容和我对GoF原文的理解存在出入。尤其很多文章会将“抽象工厂”和“工厂方法”作为竞争关系来对比,并且明确指出了各自的使用场景。
本文会聊聊我的一些理解,并在后面写一个使用两种模式的小例子,欢迎拍砖。
GoF23种设计模式中的抽象工厂模式(Abstrct Factory)与工厂方法模式(Factory Method)。
要么使用“工厂方法模式”,要么使用“抽象工厂模式”, 两者是完全的竞争关系。这句话是正确的吗?
下面放一张本文的脑图。
抽象工厂意图:提供一个创建一系列相关或相互依赖对象的接口, 而无需指定一个具体的类。(这句是GoF设计模式原文)
我的理解:
“抽象工厂”的主体是“工厂”,要有一个工厂。
当调用者需要创建一个具体类的实例时,并不让调用者直接进行实例化的操作, 而是提供给调用者一个抽象工厂(该工厂有创建一系列对象的接口),调用者通过调用抽象工厂的接口去实例化对象,调用者与抽象工厂的关系是关联关系, 即调用者"有"一个抽象工厂。
工厂方法意图:定义一个用于创建对象的接口, 让子类决定实例化哪一个类。(这句是GoF设计模式原文)
我的理解:
“工厂方法”的主体是“方法”,“工厂”是用来描述方法的作用(即创建一个实例)。
一个类自身有创建对象的接口, 但自身接口是抽象的或默认的实现, 真正的实现是某个具体的子类去做, 该类与子类之间的关系是泛化关系。
两种模式都可以单独使用,也可以结合使用,二者并非完全的竞争关系。
“抽象工厂模式”的具体工厂实现常常使用了“工厂方法模式”,“抽象工厂模式”也可以不使用“工厂方法模式”(例如具体工厂使用“原型模式”实现)。
现在我们要实现一个"执行器", 需要做以下几件事:
ObjectBase及其子类的代码如下:
//基础Object
public class ObjectBase {
public void execute() {
System.out.println("I'm objectBase.");
}
}
//ObjectBase的子类
public class ObjectB extends ObjectBase{
public void execute() {
System.out.println("I'm objectB.");
}
}
//ObjectBase的子类
public class ObjectA extends ObjectBase{
public void execute() {
System.out.println("I'm objectA.");
}
}
ValidatorBase及其子类代码如下:
public class ValidatorBase {
public void validate(ObjectBase object) {
System.out.println("I'm ValidatorBase.");
}
}
//ValidatorBase的子类
public class ValidatorA extends ValidatorBase{
public void validate(ObjectBase object) {
System.out.println("I'm ValidatorA.");
}
}
//ValidatorBase的子类
public class ValidatorB extends ValidatorBase{
public void validate(ObjectBase object) {
System.out.println("I'm ValidatorB.");
}
}
单独使用工厂方法模式是可以的, 没有工厂类, 不需要去实例化一个“工厂”。
//基础执行器
public class ObjectExecutor {
private ObjectBase object;
private ValidatorBase validator;
public void execute() {
//调用两个工厂方法, 创建ObjectBase和ValidatorBase的实例
this.object = createObject();
this.validator = createValidator();
//验证器验证。
validator.validate(object);
//调用执行方法
object.execute();
}
//工厂方法, 创建一个ObjectBase类型的对象, 在本例中该工厂方法非抽象,有一个默认实现。
public ObjectBase createObject() {
return new ObjectBase();
}
//工厂方法, 创建一个ValidatorBase的对象, 在本例中该工厂方法非抽象,有一个默认实现。
public ValidatorBase createValidator() {
return new ValidatorBase();
}
}
当我们想创建ObjectA类的对象,并搭配一个ValidatorA类型的验证器时,需要有一个ObjectAExecutor类(作为ObjectExecutor类的子类去决定实例化的类型),上面代码中ObjectExecutor类与该类的关系是 泛化关系。
public class ObjectAExecutor extends ObjectExecutor {
//子类重写了父类的工厂方法, 创建什么类型的对象由该子类决定。
@Override
public ObjectBase createObject() {
return new ObjectA();
}
//子类重写了父类的工厂方法
@Override
public ValidatorBase createValidator() {
return new ValidatorA();
}
}
想调用ObjectB类对象的方法时,同理要有一个ObjectBExecutor类。
public class ObjectBExecutor extends ObjectExecutor{
@Override
public ObjectBase createObject() {
return new ObjectB();
}
@Override
public ValidatorBase createValidator() {
return new ValidatorB();
}
}
调用示例
public class Main {
public static void main(String[] args) {
ObjectExecutor objectExecutor = new ObjectExecutor();
objectExecutor.execute();
objectExecutor = new ObjectAExecutor();
objectExecutor.execute();
objectExecutor = new ObjectBExecutor();
objectExecutor.execute();
}
}
基础执行器类中不再直接包含两个“工厂方法”,而是需要指定一个"抽象工厂"的实例。创建具体的Object和Validator的事情都交给"抽象工厂"去做。
抽象工厂实现:
//一个 真--抽象工厂
public abstract class AbstractFactory {
//这里使用了工厂方法模式
//这是抽象工厂中的工厂方法(实例化交给子类去做)
public abstract ObjectBase createObject();
//这是抽象工厂中的工厂方法(实例化交给子类去做)
public abstract ValidatorBase createValidator();
}
//基础执行器, 使用了抽象工厂模式
public class ObjectExecutor {
private ObjectBase object;
private ValidatorBase validator;
//ObjectExecutor 有(has a) 抽象工厂
private AbstractFactory factory;
//执行方法,调用object的execute()方法。
public void execute() {
this.object = factory.createObject();
this.validator = factory.createValidator();
validator.validate(object);
object.execute();
}
public void setFactory(AbstractFactory factory) {
this.factory = factory;
}
}
有两个具体工厂AFactory和BFactory, AbstractFactory与它们之间的关系是 泛化关系
//抽象工厂模式的具体工厂
public class AFactory extends AbstractFactory{
//这是子类中工厂方法的实现
@Override
public ObjectBase createObject() {
return new ObjectA();
}
//这是子类中工厂方法的实现
@Override
public ValidatorBase createValidator() {
return new ValidatorA();
}
}
//抽象工厂模式的具体工厂
public class BFactory extends AbstractFactory{
//这是子类中工厂方法的实现
@Override
public ObjectBase createObject() {
return new ObjectB();
}
//这是子类中工厂方法的实现
@Override
public ValidatorBase createValidator() {
return new ValidatorB();
}
}
调用:
public class Main {
public static void main(String[] args) {
ObjectExecutor objectExecutor = new ObjectExecutor();
//将具体的A工厂设置给objectExecutor
objectExecutor.setFactory(new AFactory());
objectExecutor.execute();
//将具体的B工厂设置给objectExecutor
objectExecutor.setFactory(new BFactory());
objectExecutor.execute();
}
}
在有类似"产品族"或一组"相关"、“相互依赖”的对象需要创建时, 去思考“抽象工厂模式”在这个场景下是否适用,这应该是一个很不错的习惯。
很多“抽象工厂模式”的具体工厂实现都是使用了“工厂方法模式”的,二者应该不是非此即彼的关系。
“抽象工厂模式"的具体工厂也可以不使用"工厂方法模式"实现, 例如可以使用"原型模式”。
单独使用“工厂方法模式“与使用”抽象工厂模式+工厂方法模式“在某些场景其实是可以互换的, 并没有绝对的优劣之分, 还是要具体问题具体分析。