作者:汤圆

个人博客: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就可以了);

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

总结

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

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

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

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