什么是工厂模式?

我的总结是: 遵守软件设计中的开闭原则和依赖反转原则, 并且客户端只需通过参数来创造多个对象, 并且在创建过程中,创建对象的过程对客户端是透明的. 这种开发模式叫做工厂模式.

出现原因.

我们在java中创建对象最入门的方法就是

ClassXXX xx = new ClassXXX();
xx.MM();

但当需要创建的同种类型的对象较多时, 重复的代码就会很多, 这样的写法就显得略过于臃肿, 并且混乱.

于是人们创造了“由一个第三方专门负责创建对象”的这么一种设计模式.

简单来说, 工厂模式分为三步:

  1. 总结出要创建的对象的特征, 将其抽象成接口
  2. 各类型的实现方法
  3. 创造工厂类, 输入接口,输出具体实现类.

废话不多说, 上demo

比如我们想要创建一个乐队, 这个乐队有吉他手,有钢琴手. 假设我们想要像流水线一样生产这群成员.

按工厂模式的步骤, 我们首先创建出乐器的规则(即接口) (假设我们不需要活人,有乐器就可以自动弹奏)

public interface Instrument {
    public void play();
}

以及两个乐器的实现类, 钢琴和吉他.

public class Guitar implements Instrument{
    @Override
    public void play() {
        System.out.println("playing guitar");
    }
}

public class Piano implements Instrument {
    @Override
    public void play() {
        System.out.println("playing Piano");
    }
}

这样, 我们的第一步和第二步就完成了.

下面是第三步, 创建工厂方法

public class InstrumentFactory {
    public Instrument export(String inst){
        if (inst=="guitar"){
            return new Guitar();
        }
        return new Piano();
    }
}

这样, 一个最简单的工厂模式就出来了.

我们在main 方法中调用

public class Main {
    public static void main(String[] args) {
        InstrumentFactory factory = new InstrumentFactory();
        factory.export("guitar").play();
        factory.export("piano").play();
    }

结果是:

playing guitar
playing Piano

当然, 程序如果这样写, 肯定是不行的. 关键点在于factory的输入太过于不专业.

所以, 下面我们对这个最简单的工厂模式做一下改良.

我们使用泛型改一下factory的输入.

public class InstrumentFactory {
    public Instrument export(Class<? extends Instrument> instClass) throws IllegalAccessException, InstantiationException {
        return instClass.newInstance();
    }
}

而在main方法里, 只需要将输入由String改成class即可

InstrumentFactory factory = new InstrumentFactory();
factory.export(Guitar.class).play();
factory.export(Piano.class).play();

这样, 一个最简单的工厂模式就被写出来了. 很简单吧? 我们在研究JDK源码或Spring源码(尤其是Spring底层的Spring Data时), 他们使用的工厂模式和我们写的这个工厂模式也没有太大的区别. 很多时候研究源码觉得眼花缭乱,是因为很多的源码都是把多种设计模式混在一起. 如果我们把设计模式各个击破, 再去看源码,就会有“一览众山小”的感觉了.


你以为这样就结束了吗?

我们还差一步. 上面的部分仅仅是一个简单的工厂模式, 实际上它就叫做简单工厂模式(“Simple Factory Pattern”). 在GOF的23种设计模式里, 简单工厂模式是并不在其中的.

我们想要让你的代码登上大雅之堂, 还是需要做一番改良, 让他更符合标准.

这时我们就需要思考了, 我们的简单工厂模式哪里有问题呢? 或者说, 哪里不规范呢?

我们会发现, 我们创建的工厂是一个“万能工厂”,它既能造吉他, 也能造钢琴. 世界上有这样的工厂吗? 也许有, 但是在软件的世界里, 不要忘了还有一个原则叫“单一职责”的原则.

我在这篇文章的开头提到了开闭原则依赖倒置原则. 这两个原则的意思是: 一个软件,或是一种功能,要对修改关闭, 对扩展开放, 简而言之就是易于扩展, 可多处复用. 以及, 要让底层依赖高层, 而不是高层依赖底层.

那么单一职责原则又是什么呢?

行话叫做: 不能存在多于一个导致类变更的原因.

在我们创建的factory中, guita的实现和piano的实现都会导致factory类被改变.

所以我们要修复一下这个问题.

我们可以把factory抽象出来, 并用多个工厂实现工厂的抽象类. 让一个工厂只负责一种对象.

public interface IFactory {
    public void play();
}
public class GuitaFactory implements IFactory {
    @Override
    public Instrument generate() {
        return new Guitar();
    }
}
public class PianoFactory implements IFactory{
    @Override
    public Instrument generate() {
        return new Piano();
    }
}

在main 方法中, 我们使用以下方法使用出厂的乐器

                IFactory guitarFactory = new GuitaFactory();
        IFactory pianoFactory = new PianoFactory();
        guitarFactory.generate().play();
        pianoFactory.generate().play();

这就是一个标准的工厂模式.

你的代码终于可以带上规范化的标签, 登上GOF24的大雅之堂, 与各类高手坐在一起谈笑风生了.


yizheng
301 声望27 粉丝

一蓑烟雨任平生