聊聊设计模式之抽象工厂与工厂方法,两者是竞争关系吗?

关于设计模式中的“抽象工厂模式”与“工厂方法模式”,我浏览过网络上面的一些资料和文章,也拜读了GoF的《设计模式》,发现部分网络上的内容和我对GoF原文的理解存在出入。尤其很多文章会将“抽象工厂”和“工厂方法”作为竞争关系来对比,并且明确指出了各自的使用场景。

本文会聊聊我的一些理解,并在后面写一个使用两种模式的小例子,欢迎拍砖。

本文讨论范围

GoF23种设计模式中的抽象工厂模式(Abstrct Factory)与工厂方法模式(Factory Method)。

抛出一个问题

要么使用“工厂方法模式”,要么使用“抽象工厂模式”, 两者是完全的竞争关系。这句话是正确的吗?


下面放一张本文的脑图。

聊聊设计模式之抽象工厂与工厂方法,两者是竞争关系吗?_第1张图片


两种模式分辨之我见

抽象工厂

抽象工厂意图:提供一个创建一系列相关或相互依赖对象的接口, 而无需指定一个具体的类。(这句是GoF设计模式原文)

我的理解:

“抽象工厂”的主体是“工厂”,要有一个工厂。

当调用者需要创建一个具体类的实例时,并不让调用者直接进行实例化的操作, 而是提供给调用者一个抽象工厂(该工厂有创建一系列对象的接口),调用者通过调用抽象工厂的接口去实例化对象,调用者与抽象工厂的关系是关联关系, 即调用者"有"一个抽象工厂。

工厂方法

工厂方法意图:定义一个用于创建对象的接口, 让子类决定实例化哪一个类。(这句是GoF设计模式原文)

我的理解:

“工厂方法”的主体是“方法”,“工厂”是用来描述方法的作用(即创建一个实例)。

一个类自身有创建对象的接口, 但自身接口是抽象的或默认的实现, 真正的实现是某个具体的子类去做, 该类与子类之间的关系是泛化关系。

两种模式的关系

两种模式都可以单独使用,也可以结合使用,二者并非完全的竞争关系。
“抽象工厂模式”的具体工厂实现常常使用了“工厂方法模式”,“抽象工厂模式”也可以不使用“工厂方法模式”(例如具体工厂使用“原型模式”实现)。

现在我们要实现一个"执行器", 需要做以下几件事:

  1. 创建一个"ObjectBase"类型的对象。
  2. 创建一个"ValidatorBase"类型的对象, 执行该对象的validate(ObjectBase object)方法。
    特定的ValidatorBase类型需要与特定的ObjectBase类型对象搭配使用,例如ValidatorA 要与 ObjectA搭配使用, ValidatorB 要与 ObjectB搭配使用。
  3. 执行ObjectBase类型对象的execute()方法。

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();
    }

}

一些思考与总结

在有类似"产品族"或一组"相关"、“相互依赖”的对象需要创建时, 去思考“抽象工厂模式”在这个场景下是否适用,这应该是一个很不错的习惯。

很多“抽象工厂模式”的具体工厂实现都是使用了“工厂方法模式”的,二者应该不是非此即彼的关系。

“抽象工厂模式"的具体工厂也可以不使用"工厂方法模式"实现, 例如可以使用"原型模式”。

单独使用“工厂方法模式“与使用”抽象工厂模式+工厂方法模式“在某些场景其实是可以互换的, 并没有绝对的优劣之分, 还是要具体问题具体分析。

你可能感兴趣的:(设计模式,后端)