简单工厂模式

工厂模式用于实现逻辑的封装,并通过公共的接口提供对象的实例化服务,在添加新的类时只需做少量的修改。

TeaFactory 类中包含 GreenTeaRedTeaGuanYinTea 的实例化方法 createTea(),当客户需要对象时,调用 TeaFactorycreateTea() 方法,并传所需的对象类型即可。TeaFactory 实例化相应的对象(如 GreenTea)并返回,返回的对象被转换为基类类型。

简单工厂模式流程

静态工厂模式

新增工厂类 TeaFactory ,用于创建 Tea 实例。

  1. 创建抽象类 Tea 及继承它的三个具体类 GreenTeaRedTeaGuanYinTea
public abstract class Tea {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    public void drink() {
        System.out.println("喝茶......");
    }
}
public class GreenTea extends Tea {
    @Override
    public void drink() {
        System.out.println("喝绿茶");
    }
}

public class RedTea extends Tea{
    @Override
    public void drink() {
        System.out.println("喝红茶");
    }
}

public class GuanYinTea extends Tea{
    @Override
    public void drink() {
        System.out.println("喝铁观音");
    }
}
  1. 创建工厂类;
public class TeaFactory {

    public enum TeaTypeEnum {
        /**
         * 绿茶、红茶、铁观音
         */
        GREEN_TEA,
        RED_RED,
        GUAN_YIN_TEA
    }

    public static Tea createTea(TeaTypeEnum type) {
        switch (type) {
            case GREEN_TEA:
                return new GreenTea();
            case RED_RED:
                return new RedTea();
            case GUAN_YIN_TEA:
                return new GuanYinTea();
            default:
                return null;
        }
    }

    public static void main(String[] args) {
        // 测试
        Tea tea = TeaFactory.createTea(TeaTypeEnum.RED_RED);
        // 输出:喝红茶
        tea.drink();
    }
}

TeaFactory 只负责 Tea 类的实例化,符合单一职责原则;但是当我们需要新增一个新的 Tea 类时,需要修改 TeaFactory 的代码,这就有一定的局限性了。

我们可以改进这种简单工厂模式,使用注册的新类在使用时才被实例化,从而保证其对外扩展开放。

改进的简单工厂模式

  1. Tea 类中新增抽象方法;
/**
* 用于返回实例
* @return
*/
abstract public Tea newInstance();
  1. 在其他三个具体类 GreenTeaRedTeaGuanYinTea 中实现抽象的方法,返回对应的实例;
public class GreenTea extends Tea {

    @Override
    public Tea newInstance() {
        return new GreenTea();
    }

    @Override
    public void drink() {
        System.out.println("喝绿茶");
    }
}

public class RedTea extends Tea{
    @Override
    public Tea newInstance() {
        return new RedTea();
    }

    @Override
    public void drink() {
        System.out.println("喝红茶");
    }
}

public class GuanYinTea extends Tea{

    @Override
    public Tea newInstance() {
        return new GuanYinTea();
    }

    @Override
    public void drink() {
        System.out.println("喝铁观音");
    }
}
  1. 在工厂类 TeaFactory 中,使用 Map 对象来保存具体类的标签和对应的类;
/**
 * 使用 Map 对象来保存 Tea 和对应的类
 */
private static Map<String, Tea> registeredTeas = new HashMap<>();
  1. 新增方法 registerTea() ,用于添加新的 Tea 类;
public static void registerTea(String teaTag, Tea tea) {
    registeredTeas.put(teaTag, tea);
}
  1. 新增方法 getTea() ,用于获取对应的类;
public static Tea getTea(String teaTag) {
    return registeredTeas.get(teaTag) == null ? null : registeredTeas.get(teaTag).newInstance();
}
  1. 测试
public static void main(String[] args) {
    // 添加 GreenTea
    TeaFactory.registerTea("green", new GreenTea());
    TeaFactory.registerTea("red", new RedTea());
    // 添加其他的 Tea 类......

    Tea tea = TeaFactory.getTea("red");
    if (null == tea) {
        System.out.println("获取实例失败");
        return;
    }
    // 输出:喝红茶
    tea.drink();
}

工厂方法模式

工厂方法模式是在静态工厂模式上做的改进。工厂类被抽象化,用于实例化具体类的代码被转移到了子类。

在本例中,不同地区的茶叶工厂受制于环境等因素影响,杭州西湖一带生产的绿茶较好(仅举例说明),福建一带的产的红茶品质较好。为了效益和产品品质,商家决定在各个地区创办工厂,绿茶工厂仅能生产绿茶,红茶工厂仅能生产红茶。

本例工厂方法模式实现如下图所示:

工厂方法模式

AbstractTeaFactory 提供创建实例的方法,但不包含创建新实例的代码,拥有子类 GreenTeaFactoryRedTeaFactoryGreenTeaFactory 用于生产绿茶,如 LongjingTea(龙井)、MaojianTea(毛尖);RedTeaFactory 用于生产红茶,如 JinjunmeiTea(金骏眉)、BairuixiangTea(百瑞香)。

  1. 新建 Tea2 类及其子类 LongjingTeaMaojianTeaJinjunmeiTeaBairuixiangTea
public abstract class Tea2 {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
  1. 新增抽象工厂类,请注意该工厂类不包含任何创建新实例的代码;
public abstract class AbstractTeaFactory {

    /**
     * 生产
     * @param teaTag tag
     * @return
     */
    protected abstract Tea2 createTea(String teaTag);

    public Tea2 setTeaName(String teaTag, String teaName) {
        Tea2 tea = createTea(teaTag);
        tea.setName(teaName);
        return tea;
    }
}
  1. 新增 AbstractTeaFactory 子类,如生产绿茶的工厂 GreenTeaFactory,重写父类的 createTea() 方法,用于创建具体的实例;
public class GreenTeaFactory extends AbstractTeaFactory {

    @Override
    protected Tea2 createTea(String teaTag) {
        if ("longjing".equals(teaTag)) {
            return new LongjingTea();
        } else if ("maojian".equals(teaTag)) {
            return new MaojianTea();
        } else {
            return null;
        }
    }
}

在客户端,实例化工厂类并创建实例:

GreenTeaFactory teaFactory = new GreenTeaFactory();
teaFactory.setTeaName("longjing", "龙井");
  1. 同理,创建 RedTeaFactory,用于生产红茶;
public class RedTeaFactory extends AbstractTeaFactory {
    @Override
    protected Tea2 createTea(String teaTag) {
        if ("jinjunmei".equals(teaTag)) {
            return new JinjunmeiTea();
        } else if ("baituixiang".equals(teaTag)) {
            return new BairuixiangTea();
        } else {
            return null;
        }
    }
}

在客户端,实例化工厂类并创建实例:

RedTeaFactory redTeaFactory = new RedTeaFactory();
redTeaFactory.setTeaName("jinjunmei", "金骏眉");

后来,市场上又流行了黑茶,商家决定迎合市场,进一步扩展业务,创建了黑茶工厂,用于生产黑茶类产品。因此我们建一个黑茶工厂 BlackTeaFactory

public class BlackTeaFactory extends AbstractTeaFactory{
    @Override
    protected Tea2 createTea(String teaTag) {
        if ("puer".equals(teaTag)) {
            return new PuerTea();
        }
        return null;
    }
}

生产黑茶类产品:

BlackTeaFactory blackTeaFactory = new BlackTeaFactory();
blackTeaFactory.setTeaName("puer", "普洱茶");

抽象工厂模式

抽象工厂模式是工厂方法模式的扩展,它不再是创建单一类型的对象,而是创建一系列相关联的对象。

在本例中,红茶工厂为了迎合当地市场需求,丰富其产品线,引入了新的产品:奶茶;而绿茶工厂引入了果汁。如果使用工厂方法模式,我们还得新增奶茶和果汁工厂及对应的奶茶和果汁实体类,万一以后还新增产品,则添加的类越来越多。

在这里,我们可以将奶茶、果汁作为『饮料』类产品生产,将绿茶、红茶作为『茶叶』类产品生产。每个类型有对应的工厂类。

整体结构图:

抽象工厂模式

  1. 新增抽象产品类,对应『茶叶』和『饮料』类;
public abstract class AbstractTea {
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    private String name;

    public void sell() {
        System.out.println("卖茶叶啦");
    }
}
public abstract class AbstractDrinks {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void sell() {
        System.out.println("卖饮料啦");
    }
}
  1. 新建具体产品类 LongjingTea2MaojianTea2FruitJuiceTeaWithMilk
public class LongjingTea2 extends AbstractTea{
    @Override
    public void sell() {
        System.out.println("卖龙井茶啦");
    }
}

public class MaojianTea2 extends AbstractTea{
    @Override
    public void sell() {
        System.out.println("卖毛尖茶啦");
    }
}

public class FruitJuice extends AbstractDrinks {

    @Override
    public void sell() {
        System.out.println("卖果汁啦");
    }
}

public class TeaWithMilk extends AbstractDrinks{
    @Override
    public void sell() {
        System.out.println("卖奶茶啦");
    }
}
  1. 新建抽象工厂接口 AbstractFactory,用于声明创建不同种类产品的方法;
public abstract class AbstractFactory {

    /**
     * 生产茶叶
     * @param teaTag 标签
     * @return
     */
    public abstract AbstractTea createTea(String teaTag);

    /**
     * 生产饮料
     * @param type 类型
     * @return
     */
    public abstract AbstractDrinks createDrinks(String type);
}
  1. 新建具体工厂类 TeaFactory2DrinksFactory,用于实现抽象工厂类中声明的方法,创建具体实例;
public class TeaFactory2 extends AbstractFactory{
    @Override
    public AbstractTea createTea(String teaTag) {
        if ("longjing".equals(teaTag)) {
            return new LongjingTea2();
        } else if ("maojian".equals(teaTag)) {
            return new MaojianTea2();
        } else {
            return null;
        }
    }
    @Override
    public AbstractDrinks createDrinks(String type) {
        return null;
    }
}

TeaFactory2 只负责生产龙井、毛尖等茶类。

public class DrinksFactory extends AbstractFactory{
    @Override
    public AbstractTea createTea(String teaTag) {
        return null;
    }
    @Override
    public AbstractDrinks createDrinks(String type) {
        if ("fruitjuice".equals(type)) {
            return new FruitJuice();
        } else if ("teawithmilk".equals(type)) {
            return new TeaWithMilk();
        } else {
            return null;
        }
    }
}

DrinksFactory 只负责生产果汁、奶茶等饮料。

  1. 在客户端中使用;
public static void main(String[] args) {
    AbstractFactory abstractFactory = new DrinksFactory();
    AbstractDrinks drinks = abstractFactory.createDrinks("fruitjuice");
    drinks.sell();

    AbstractFactory abstractFactory1 = new TeaFactory2();
    AbstractTea tea = abstractFactory1.createTea("longjing");
    tea.sell();
}

总结

工厂模式的核心就是由工厂类来负责合适对象的实例化,实现工厂模式的三种方式(简单工厂模式、工厂方法模式、抽象方法模式)之间可能存在许多重叠的地方,况且,这些模式也没有明确的定义,如果存在困惑也很正常。结合工作中的需求,选择合适自己最简单那种就行。

参考文献

[1]. 《Java设计模式及实践》

文章目录