一般来说工厂模式分为三种,分别是简单工厂模式,工厂方法模式和抽象工厂模式。
工厂模式为什么会产生?最直接的原因是为了控制new,用工厂模式后不用我们自己new对象,而是让工厂生产出对象。
1.简单工厂
我们经常会遇到一种场景,那就是根据不同条件来new不同的对象。这是我们会写几个
if else来控制具体new哪个对象。简单工厂不过是把这段if else的代码移到单独一个类里
去了而已。这样做的好处也显而易见。那就是不用在很多类里new对象了,如果有修改的话只用修改这个工厂类即可。严格来说简单工厂模式并不是一个设计模式,反而比较像是一种编程习惯。
2. 工厂方法模式(Factory Method Pattern)
所有工厂模式都是用来封装对象的创建。工厂方法模式通过让子类决定该创建什么对象,来达到封装对象的创建的目的。
具体的估计是父类里有一个抽象方法factoryMethod,由它的子类来具体实现factoryMethod,决定new哪个对象(也就是简单工厂里的if else那段代码)。每个子类其实可以说是一个简单工厂。由此可以看出工厂方法模式和简单工厂很相似。
那么工厂方法模式相对于简单工厂来说有什么优点呢?虽然简单工厂也对对象的创建进行了封装,但是如果我们需要多加一个条件呢?必须得修改简单工厂里的代码。但是工厂方法模式则不需要修改之前的代码,只需要新增一个子类,由这个子类来实现具体的对象创建即可。这样就遵守了开放(易于扩展)封闭(不修改原来的代码)原则。
3. 抽象工厂模式
在说这个模式之前,我想分享下《Head First设计模式》一书中一些有用的概念和解释。
当你直接实例化一个对象时,就是在依赖它的具体类,如果一个类里实例化了5个类,那么就相当于它依赖了这5个类。很明显,代码里减少对于具体类的依赖是件好事,有一个设计原则正式阐明了这一点:要依赖抽象,不要依赖具体类。这个原则还有一个名称:依赖倒置原则(Dependecy Inversion Principle)。
具体来说,这个原则有如下原则:
- 变量不可以持有具体类的引用。
- 不要让类派生自具体类。
- 不要覆盖基类中已实现的方法。
要完全遵守这几个原则几乎不太可能。但有些时间我们不用遵守,比如有一个类是不会改变的类,那么在代码中直接实例化具体类也就没什么大碍。
抽象工厂模式其实本质上还是工厂方法模式,只不过是多个工厂方法,一般用来解决产品家族的场景。比如有一个水果工厂,生产苹果和香蕉(暂定只生产这两种)。水果工厂又可以分为南方水果工厂和北方水果工厂。这时我们定义一个抽象类FruitFactory,里面有两个抽象方法createApple()和createBnana()。南方水果工厂SouthFruitFactory和北方水果工厂NorthFruitFactory继承于FruitFactory,具体实现createApple()和createBnana()这两个方法。这其实就是两个工厂方法。
这时如果我们需要增加一个中部水果工厂呢?对,我们只需要新建一个MiddleFruitFactory继承于FruitFactory,实现createApple()和createBnana()方法即可。
可以看到,这个模式对象产品家族的扩展是很方便的。但是这个模式也有一个缺点就是,要先确定好产品家族的产品结构,不适合增加产品。比如上面例子里的苹果和香蕉,试想如果我们想让工厂增加生产一个产品梨子,那么不是得所有工厂都得修改?
总体来说,工厂模式让我们针对抽象编程,而不要针对具体类编程。