设计模式不是模板,是在遇到复杂场景的时候,提供一种设计思路。谨记:不要生搬硬套,不要把简单的问题变复杂。
工厂方法模式,在23中设计模式中属于创建型设计模式,简单来说就是只对结果负责,不要三无产品。
在介绍工厂方法方法模式之前,先看下不用设计模式的代码,以牛奶为例,一个销售平台,提供多个牌子的牛奶,客户在购买每种牛奶的时候写法:
Telunsu telunsu=new Telunsu();//特仑苏牛奶
Yili yili=new Yili();//伊利牛奶
简单来说,就是客户端要哪种牛奶,我们创建一个(通过new一个对象)。这种方式当然可以解决问题。接下来看下用设计模式的写法和思想。
一. 简单工厂模式
简单工厂模式的思路,先定义一个工厂(一个工厂类),提供一个方法用于创建每个牌子的牛奶,再定义一个牛奶的接口,每种牌子的牛奶都实现这个接口
public class SimpleFactory {
/**
* Milk 是一个接口 每种牛奶都实现了这个接口
* @param name 传入牛奶的名字
* @return 通过判断传入的参数,返回不同牌子的牛奶
*/
public Milk getMilk(String name){
if ("telunsu".equals(name)){
return new Telunsu();
}
if ("yili".equals(name)){
return new Yili();
}
return null;
}
}
很好理解,这个方法用于接收客户端想拿到的牛奶的名字,拿到之后这个工厂加以创建并返回给客户端,接着看下客户端的调用过程:
SimpleFactory simpleFactory=new SimpleFactory();
Milk telunsu = simpleFactory.getMilk("telunsu");
Milk yili = simpleFactory.getMilk("yili");
通过建立一个工厂,并在每个牌子的牛奶上都实现了Milk接口,我们可以通过名字拿到牛奶(也可以通过别的属性,自定义),这样做的好处是客户在拿牛奶的时候看不到生产过程,什么是生产过程,new出来的就是生产过程,因为在实际应用中,创建一个牌子牛奶,往往是很复杂的,简单来说,就是在new的过程中需要进行每个参数的赋值操作,也会有一些别的类的引用,导致客户端只想要一个特仑苏牛奶,我们每次都进行了一大堆操作,这个过程当然也可以进行优化,这里不进行阐述。
再实现了简单工厂模式之后,客户端只要告诉工厂我要牛奶的名字即可,创建全部交由这个工厂去实现。
二. 工厂方法模式
在实现了简单工厂模式之后,考虑到一个问题,如果要添加一个新牌子的牛奶,这时候,需要在getMilk方法中加一个if语句,这有点违背了设计模式的开闭原则(开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。)当然在拓展业务的时候,不去修改原有的代码是非常难做到的,但在设计之初,能设计出尽量满足开闭原则的代码是我们要追求的,简单工厂模式还有一个弊端就是客户端需要传入牛奶的名字(也可以是别的),这里是一个字符串,这往往加大程序放生错误的几率。所以工程方法模式出现了。
工厂方法模式就是讲一个简单的工厂,分为多个工厂,在上面的例子中,一个工厂创建了所有牌子的牛奶,其实这是不符合现代化的实际情况的,应该是每种牌子的牛奶都交由一个工厂去生产,也就说想要特仑苏牛奶,通过特仑苏牛奶工厂去创建,想要伊利牛奶,通过伊利牛奶去创建。看下这种模式下的代码:
public interface Factory {
Milk getMilk();
}
这里先构造一个工厂接口,就是用来生产牛奶的,生产什么牛奶,由实现这个接口的每个工厂去完成。
public class TeFactory implements Factory {
@Override
public Milk getMilk() {
return new Telunsu();
}
}
特仑苏的工厂实现了工厂接口,并且在getMilk方法里创建特仑苏牛奶,伊利牛奶一样的操作,代码省略。也就是实现一个目的:专人做专事。下面在看下客户端调用的方式:
// 特仑苏工厂
Factory teFactory=new TeFactory();
// 特仑苏工厂生产特仑苏
Milk telunsu = teFactory.getMilk();
// 伊利工厂
Factory yiFactory=new YiFactory();
// 伊利工厂生产伊利
Milk yili = yiFactory.getMilk();
这样我们完成了每个工厂生产每种牛奶,同样的,客户端并不会知道我们生产的具体过程。
三. 抽象工厂模式
上面介绍了简单工厂和方法工厂,最后介绍下抽象工厂。
抽象工厂模式是在开发中用的比较多的一种工厂设计模式,它可以说是对工厂方法模式的一种改进,在上面的工厂方法模式中,我们生产一种牛奶就要出现一个工厂类,但往往在实际开发中,制作牛奶会有一些相同的标准,我们可以用一个抽象工厂把这些共同的方法提炼出来。抽象工厂还可以减少我们创建的工厂类。看下代码实现:
public abstract class AbstractFactory {
//公共的逻辑
//方便于统一管理
/**
* 获得一个蒙牛品牌的牛奶
* @return
*/
public abstract Milk getMengniu();
/**
* 获得一个伊利品牌的牛奶
* @return
*/
public abstract Milk getYili();
}
定义了一个抽象工厂,抽象工厂里面两个抽象方法分别对应两种品牌的牛奶,抽象工厂面可以有一些公共的逻辑。接着我们去继承这个抽象工厂。
public class MilkFactory extends AbstractFactory {
@Override
public Milk getYili() {
return new Yili();
}
@Override
public Milk getTelunsu() {
return new Telunsu();
}
}
到这里就很明了了,我们想要拿到特仑苏或者伊利,只要构造出这个牛奶工厂就可以。
MilkFactory factory = new MilkFactory();
Milk telunsu = factory.getSanlu();
Milk yili = factory.getYili();
抽象工厂的实现,解决了每个工厂生产每个牌子的牛奶(牛奶工厂的每个方法),在需要添加一个新品种的牛奶,我们只要在抽象工厂里面去写一个抽象方法,然后再牛奶工厂实现类里去实现即可,并且抽象工厂里面每个牛奶都可以继承公共方法,加以复用。
上面实现了3种工厂设计模式,客户端不需要知道我们牛奶的创建过程,只要拿到牛奶。工厂设计模式可以说也是在开发中用的比较多的一种,很多的情景都可以用工厂模式。但还是要记住,不要把一个简单的问题变复杂。不要就一个new 可以完成的功能去改写成工厂模式。关于设计模式还是要多思考。