什么是工厂模式?
我的总结是: 遵守软件设计中的开闭原则和依赖反转原则, 并且客户端只需通过参数来创造多个对象, 并且在创建过程中,创建对象的过程对客户端是透明的. 这种开发模式叫做工厂模式.
出现原因.
我们在java中创建对象最入门的方法就是
ClassXXX xx = new ClassXXX();
xx.MM();
但当需要创建的同种类型的对象较多时, 重复的代码就会很多, 这样的写法就显得略过于臃肿, 并且混乱.
于是人们创造了“由一个第三方专门负责创建对象”的这么一种设计模式.
简单来说, 工厂模式分为三步:
- 总结出要创建的对象的特征, 将其抽象成接口
- 各类型的实现方法
- 创造工厂类, 输入接口,输出具体实现类.
废话不多说, 上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的大雅之堂, 与各类高手坐在一起谈笑风生了.