作者:汤圆

个人博客:javalover.cc

前言

工厂我们都知道,就是生产东西的地方;

以前的农业时代,我们需要啥东西,都是自己做,比如椅子、桌子;

后来到了工业时代,我们需要啥东西,大部分都是工厂做,你只需要告诉工厂需要的东西。

其实软件中的工厂设计模式,也是类似:不需要我们自己去创建对象,只需要告诉工厂类,需要啥对象,工厂类会帮你创建。

下面我们循序渐进来介绍下工厂模式

目录

  • 制作一种椅子
  • 制作多种椅子
  • 创建一个椅子工厂(简单工厂模式)
  • 创建多个椅子工厂(工厂方法模式)
  • 创建多个椅子工厂(抽象工厂模式)

正文

1. 制作一种椅子

这个是最简单的了,就是谁需要,谁就创建一个,很方便;

package pattern.factory.nofactory;/** * 没有工厂,直接创建椅子 */public class NoFactory {    public static void main(String[] args) {        Chair chair = new Chair();        chair.prepare();        chair.make();        chair.box();    }    static class Chair {        public String name = "小椅子";        public void prepare() {            System.out.println(name + "的原材料是:A,B,C");        }        public void make(){            System.out.println(name + "制作中");        }        public void box(){            System.out.println(name + "打包中");        }    }}

2. 制作多种椅子

过了几天,小李觉得这种椅子不舒服,没有靠背,于是又创建了带靠背的椅子

package pattern.factory.nofactory;/** * 没有工厂,直接创建椅子(多种椅子) */public class NoFactory2 {    public static void main(String[] args) {        Chair chair = new ChairA();        chair.prepare();        chair.make();        chair.box();        Chair chairB = new ChairB();        chairB.prepare();        chairB.make();        chairB.box();    }}abstract class Chair {    public String name;    public abstract void prepare();    public void make(){        System.out.println(name + "制作中");    }    public void box(){        System.out.println(name + "打包中");    }}class ChairA extends Chair {    public ChairA() {        this.name = "小椅子";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A,B,C");    }}class ChairB extends Chair {    public ChairB() {        this.name = "靠背椅";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A2,B2,C2");    }}

这样看来,好像问题也不大;

可以是如果不止两种,而是十几种几十种呢?

此时再一个个创建就很麻烦了;

于是就有了工厂模式。

其实不止类型的增加需要工厂,数量的增加同样也需要工厂(流水线制作提高效率)

3. 创建一个椅子工厂(简单工厂模式)

简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类

小李花钱建了一个工厂,专门做各种各样的椅子,这样他每天都可以换不同的椅子坐;

大概的流程就是小李需要什么椅子,就告诉工厂,工厂来做(不再需要自己做)。

package pattern.factory.simple1;public class SimpleFactory1 {    public static void main(String[] args) {        SimpleChairFactory simpleChairFactory = new SimpleChairFactory();        simpleChairFactory.order("小椅子");        simpleChairFactory.order("靠背椅");    }}class SimpleChairFactory {    public Chair chair;    public void order(String name){        if(name == "小椅子"){            chair = new ChairA();        }else if(name == "靠背椅"){            chair = new ChairB();        }else{            chair = null;        }        if(chair != null){            chair.prepare();            chair.make();            chair.box();        }else{            System.out.println("找不到对应的椅子");        }    }}abstract class Chair {    public String name;    public abstract void prepare();    public void make(){        System.out.println(name + "制作中");    }    public void box(){        System.out.println(name + "打包中");    }}class ChairA extends Chair {    public ChairA() {        this.name = "小椅子";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A,B,C");    }}class ChairB extends Chair {    public ChairB() {        this.name = "靠背椅";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A2,B2,C2");    }}

上面这个就是简单工厂模式,通过把自己的需求告诉工厂,工厂去做出你想要的东西;

4. 创建多个椅子工厂(工厂方法模式)

工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。

上面的简单工厂模式,确实很简单,用起来也很方便;

但是有一个很大的缺点,就是如果需要增加椅子的种类,那么就需要修改工厂类的源代码;

这样一来就违背了开闭原则:对类的扩展开放,对类的修改关闭;

所以我们需要对其进行改进,创建多个工厂子类,来实现不同的创建任务。

package pattern.factory.method;/** * 工厂方法模式:将工厂类抽象出来,子类去实现对象的创建 */public class MethodFactory {    public static void main(String[] args) {        SmallChairFactory smallFactory = new SmallChairFactory();        smallFactory.order();        BackChairFactory backFactory = new BackChairFactory();        backFactory.order();    }}interface ChairFactory{    void order();}class SmallChairFactory implements ChairFactory{    public Chair chair;    public void order(){            chair = new ChairA();            chair.prepare();            chair.make();            chair.box();    }}class BackChairFactory implements ChairFactory{    public Chair chair;    public void order(){        chair = new ChairB();        chair.prepare();        chair.make();        chair.box();    }}abstract class Chair {    public String name;    public abstract void prepare();    public void make(){        System.out.println(name + "制作中");    }    public void box(){        System.out.println(name + "打包中");    }}class ChairA extends Chair {    public ChairA() {        this.name = "小椅子";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A,B,C");    }}class ChairB extends Chair {    public ChairB() {        this.name = "靠背椅";    }    @Override    public void prepare() {        System.out.println(name + "的原材料是:A2,B2,C2");    }}

5. 创建多个椅子工厂(抽象工厂模式)

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

上面的工厂方法模式,虽然解决了简单工厂模式的问题(不好扩展,单个类任务繁重),但是它本身也是有缺点的;

就是工厂方法模式中,一个工厂子类只负责生产一种产品,所以后期增加产品时,会导致工厂类过多;

这时就需要将产品进行一个简单的分类(按特定的属性分类,比如按材质分类):比如木头椅子,全都让一个厂去做;塑料椅子,让另一个厂去做。

然后每个材质的椅子,内部再按结构分类(小椅子,靠背椅);

这个就是抽象工厂模式的核心:将产品进行分类,然后分配到不同的工厂子类中。

下面这个例子是先按照材质进行大的分类,再按照结构进行小的分类:

package pattern.factory.abstract1;/** * 抽象工厂模式:将工厂类抽象出来,再把产品分类,每个子工厂生产特定类型的产品 * * 是工厂方法模式的升级版,工厂方法模式是一个工厂只做一个产品,而抽象工厂模式是一个工厂做一类产品 */public class AbstractFactory {    public static void main(String[] args) {        // 木头        WoodChairFactory woodChairFactory = new WoodChairFactory();        woodChairFactory.orderSmallChair();        woodChairFactory.orderBackChair();        // 塑料        PlasticChairFactory plasticChairFactory = new PlasticChairFactory();        plasticChairFactory.orderSmallChair();        plasticChairFactory.orderBackChair();    }}interface ChairFactory{    void orderSmallChair();    void orderBackChair();}// 木头椅子 工厂class WoodChairFactory implements ChairFactory{    public WoodChair chair;    @Override    public void orderSmallChair() {        chair = new WoodSmallChair();        chair.prepare();        chair.make();        chair.box();    }    @Override    public void orderBackChair() {        chair = new WoodBackChair();        chair.prepare();        chair.make();        chair.box();    }}// 塑料椅子 工厂class PlasticChairFactory implements ChairFactory{    public PlasticChair chair;    @Override    public void orderSmallChair() {        chair = new PlasticSmallChair();        chair.prepare();        chair.make();        chair.box();    }    @Override    public void orderBackChair() {        chair = new PlasticBackChair();        chair.prepare();        chair.make();        chair.box();    }}abstract class Chair {    public String type; // 木头/塑料    public String name; // 小椅子/靠背椅    public void prepare(){        System.out.println(type+name + "的制作步骤是:A,B,C");    }    public void make(){        System.out.println(type+name + "制作中");    }    public void box(){        System.out.println(type+name + "打包中");    }}// 木头椅class WoodChair extends Chair {    public WoodChair() {        this.type = "木头-";    }}class WoodSmallChair extends WoodChair{    public WoodSmallChair(){        this.name = "小椅子";    }}class WoodBackChair extends WoodChair{    public WoodBackChair(){        this.name = "靠背椅";    }}// 塑料椅class PlasticChair extends Chair {    public PlasticChair() {        this.type = "塑料-";    }}class PlasticSmallChair extends PlasticChair{    public PlasticSmallChair(){        this.name = "小椅子";    }}class PlasticBackChair extends PlasticChair{    public PlasticBackChair(){        this.name = "靠背椅";    }}

上面的这个抽象工厂模式的例子,虽然现在增加椅子的种类很方便了,只需要扩展一个椅子的子类就可以(比如铁的椅子,只需要创建 IronChair 继承 Chair就可以了);

但是缺点也很明显,细心的朋友可能发现了,就是如果想要增加其他结构的椅子,比如躺椅,那么就需要先改动 椅子工厂接口(增加躺椅的制作过程),再在每个实现工厂类中去实现。

总结

简单工厂模式,简单好用,缺点是不易扩展,违反了开闭原则;

工厂方法模式,可扩展,但是工厂类过多,会导致代码繁重;

抽象工厂模式,可扩展,工厂类也不会很多,但是这里的扩展只是种类层面的扩展,如果是结构层面的还是不易扩展,也会违反开闭原则。

这三种工厂模式都属于创建者型模式。