工厂模式的解读与思考

时间:2021-09-29 15:05:20

说到工厂模式,其实大家都有所耳闻,相信在我们实际的工作中也经常会用到,然而,在我个人的实际使用中来说,我觉得它最多只能算得上是一种编程习惯,但是它却被称为一种模式,所以我认为它应该有着我所不知道的可以被称为模式的使用方式,所以我去深入了解了一下


在我的实际使用中,其实很简单,就是写了一个Factory,用于加工生成一些特定的类,举例

public class TestFactory {

public Duck createDuck(String type){
Duck duck = null;
if(type.equals("blueduck")){
duck = new BuleDuck();
}else if(type.equals("blackduck")){
duck = new BlackDuck();
}
return duck;
}
}
这就是一个最简单的工厂类的对象,然后在我们需要创建对象时,就使用这个工厂类来创建实际应该需要的类


那么这就是工厂模式的全部了吗,当然不止,其实工厂模式还有两种形态


工厂方法

这种方式其实也很简单,就是将工厂写为一个抽象方法,当然每种模式都是有适用的情况的,如果比较简单的话那么最简单的工厂模式就可以满足情况了


比如我们需要一个大饼店,这个大饼店可以制作各种大饼,鞋子饼,老婆饼等等,有人来买饼,我们就根据他要的饼制作就可以了,这种情况很简单,只需要用简单的工厂模式就可以满足


那么需求扩展,我们需要开分店,北京一家,四川一家,上海一家,开分店的同时,由于地点不同,那么我们得适应各地的口味,比如,北京的鞋子饼是咸的,四川人喜欢吃辣,要辣的,上海要甜的,那么这种情况下,我们的实现就可以用上抽象方法


首先来个店的父类

<span style="font-size:18px;">/**
* 大饼店
* @author Administrator
*
*/
public abstract class PieShop {

public static final String TAG = "tag";

/**
* 创建大饼,可以看到这里不需要传入大饼的类型了,因为每个子类会自己实现
* @param type
* @return
*/
public abstract Pie createPie();

/**
* 包装大饼
*/
public void packPie(Pie pie){
Log.i(TAG, "我是大麻子品牌的大饼,使用统一包装");
}

}</span>

这里可以看到,创建大饼的方法写成了抽象方法,那么当其他子类继承时,就会需要各自实现其创建的方法

比如北京店创建咸的鞋子饼,四川实现辣的鞋子饼


那么在这里进行进行思考,这种方式跟简单的工厂方式比较,可以看到,这种方式与简单工厂的区别是将类改成了方法,那么,在这里联系到之前的策略模式,如果我将这种方式改为用一个工厂接口来实现呢,这样的话就是不会有抽相方法,而子类的唯一工作就是在某个地方替换默认的创建方法了,目前我觉得还是不错的,解析方法也可以做到复用

而代码则是这样的

/**
* 大饼店
* @author Administrator
*
*/
public abstract class PieShop {

public static final String TAG = "tag";

private PieCreateFactory mFactory = new BeijingPieCreateFactory();


/**
* 创建大饼
* @param type
* @return
*/
public Pie createPie(){
return mFactory.createPie();
}

/**
* 包装大饼
*/
public void packPie(Pie pie){
Log.i(TAG, "我是大麻子品牌的大饼,使用统一包装");
}

/**
* 大饼制作工厂的接口
* @author Administrator
*
*/
public interface PieCreateFactory{
public Pie createPie();
}

/**
* 生产北京大饼的工厂
* @author Administrator
*
*/
public class BeijingPieCreateFactory implements PieCreateFactory{

@Override
public Pie createPie() {
Pie pie = new BeijingPie();
return pie;
}

}

}

这样结合策略模式的话,其子类就只需要根据不同的商店创建不同的大饼创建类即可


但是到底采用哪种方式,还是需要在具体的项目中决断



抽象工厂

除了以上两种工厂模式之外还有一种工厂模式,成为抽象工厂,这种工厂模式的写法为:

/**
 * 大饼材料工厂的抽象接口
 * @author Administrator
 *
 */
public interface PieMaterialFactory {
<span style="white-space:pre"></span>//制造大饼所需要的面粉,每个店需要的面粉不同
<span style="white-space:pre"></span>public Flour getFlour();
<span style="white-space:pre"></span>//制造大饼所需要的芝麻,每个店需要的芝麻不同
<span style="white-space:pre"></span>public Sesame getSesame();
<span style="white-space:pre"></span>
}
先定义一个总的接口,然后,再由不同的子类去实现,这里模拟的是不同的店制造大饼时需要的材料不同


可以看到,这三种工厂模式其实说到最后就是一种,只是不断地扩展,原本的工厂类扩展为一个扩展方法,然后扩展成一群工厂方法


三种工厂模式的思考

以上三种工厂模式,说实话,就现在看起来,很平常,这在普通的程序员来说都是一个很平常的手段,我们在写代码时,对于一些有这种不同的店铺不同的方法实现一般都会采用上面的方式,无非就是分情况使用

1、只有一个地方需要根据条件创建对象时。比较简单的情况时,采用简单工厂

2、会有多个子类针对一个方法有多重创建方案时,使用抽象方法

3、针对每个方法都有不同实现需求时,采用抽象工厂


但是,这里面真的就是这么简单吗

我们再回去回顾上面的工厂模式,会发现一个问题,那就是,除了最简单的工厂模式以外,抽象方法和抽象工厂,对于bean的需求,就是都是同一个bean,北京大饼店依赖的bean是Pie,四川大饼店依赖的bean也是Pie,那么,

这个Pie就不得不写成抽象类或者接口,然后工厂方法又是可以单独封装的,这个时候我们发现一个什么现象?


那就是从最顶层的大饼店的接口,到下面实现大饼店接口的店铺,店铺内的工厂方法是可以单独实现的,但是大饼的包装、配送方法完全不需要动,然后应用到我们调用的时候,我们会发现,中间完全没有关于大饼的创建的代码,我们对于大饼有需求,要包装,要配送,但是,我们完全没有依赖具体的大饼,而是都依赖了Pie这个大饼接口

这里就发现了一个非常有帮助的原则:依赖倒置原则

这种撰写方式导致我们的代码将很难出错,修改起来也很方面,只需要修改集中的工厂实现类,我们就可以很方便地改造大饼,不管想在什么店做什么样的大饼,我们都只需要修改工厂方法内部的内容


到这里,我认为我才真正发现了工厂模式的深意所在,当然这些原则、写法、意识,还需要我在实际使用中灵活运用才能真正让我学习到这些有用的东西,找时间需要好好练习一下