代码优雅之路-设计模式之工厂模式
概述
现实中的工厂,就是造东西的,那我们生活中有哪些类型的工厂呢? 总结一下,可以分为三种:
- 自给自足的小作坊-这种工厂产能不大,但是对于重复工作有一套自己的方案
- 流水线性的大工厂-已经有了一套相对完善的机器流水线,固定的模式产能效率都有很大提升
- 完善的产业链代工厂-这时候已经可以不用关心这个东西怎么出来的,只掌握核心即可
在代码中,同样也存在现实社会中的上述三种情况,依次对应着我们熟知的简单工厂模式(小作坊),工厂方法模式(大工厂),抽象工厂模式(代工厂)。
简单工厂模式
小作坊中,往往制造某一种类商品,比如某章丘铁锅制造坊,某棉花制造坊等等,简单工厂模式(Simple Factory Pattern) 就是这样一种模式,由一特定的工厂对象,创造出指定的产品并实例化.使用起来往往只需传入要制造哪类产品(参数)即可。
现在我们用代码来清晰直观的了解下,现已中华传统美食水饺为例:
- 由于水饺有各种各样的内陷,我们做一个顶层接口作为标准
public interface IDumplings {
/**
* 各种水饺都有制作过程
*/
void make();
}
- 现在,我们准备做韭菜鸡蛋馅的水饺,并且已经录入好了制作方法
public class ChiveEggDumpling implements IDumplings {
@Override
public void make() {
System.out.println("制作韭菜鸡蛋水饺的过程");
}
}
- 现在我们开始制作韭菜水饺
public static void main(String[] args) {
//准备好韭菜馅水饺的制作工序
IDumplings dumpling = new ChiveEggDumpling();
//开始制作
dumpling.make();
}
我们来细看上面的三道工序,父类的水饺大类(IDumplings)指向了子类的韭菜馅水饺(ChiveEggDumpling),如果我们需要分别制作各类水饺,就会形成如下代码:
public static void main(String[] args) {
//准备好韭菜馅水饺的制作工序
IDumplings chiveEggDumpling = new ChiveEggDumpling();
//开始制作-韭菜馅水饺
chiveEggDumpling.make();
//准备好白菜馅水饺的制作工序
IDumplings cabbageDumpling = new CabbageDumpling();
//开始制作-白菜馅水饺
cabbageDumpling.make();
//准备好芹菜馅水饺的制作工序
IDumplings celeryDumpling = new CeleryDumpling();
//开始制作-芹菜馅水饺
celeryDumpling.make();
}
在我们的实际项目中,对象的创建过程远远要比上述代码更为复杂,即使是上述代码,我们依然会觉得臃肿,更何况在实际运用过程中,随着水饺种类越来越多,大量的类似代码迎面扑来,会不会感到窒息呢? 这是时候我们就需要用简单工厂模式对代码进行优化,总体思路就是:细节隐藏,减少依赖。
- 首先-建造水饺制作小作坊
public class DumplingFactory {
/**
* 根据你想要的吃的 获取哪种水饺
* */
public static IDumplings get(String dumplingName){
switch (dumplingName) {
case "cabbage":
return new CabbageDumpling();
case "chiveEgg":
return new ChiveEggDumpling();
case "celery":
return new CeleryDumpling();
default:
return null;
}
}
}
- 再一次制作我们要的水饺
public static void main(String[] args) {
//制作韭菜馅水饺
IDumplings chiveEgg = DumplingFactory.get("chiveEgg");
chiveEgg.make();
//制作白菜馅水饺
IDumplings cabbage = DumplingFactory.get("cabbage");
cabbage.make();
//制作芹菜馅水饺
IDumplings celery = DumplingFactory.get("celery");
celery.make();
}
大家有没有发现,最明显的区别在哪,就在于我们不需要知道哪个类制造的,我们只需要知道我们要制作哪种水饺即可。当然,小作坊毕竟是小作坊,水饺种类少了,它足以应对,但是一旦要生产几十种上百种水饺,工厂(工厂类)就要炸锅了,而且,代码本身也不符合开闭原则(开闭原则后续会单独介绍),为了解决简单工厂模式的弊端,这时候,工厂方法模式就来了。
工厂方法模式
小作坊已经无法应对我们越来越多的产品种类,这时候工厂升级了!我们需要对流水线作业进行分门别类了,一条流水线就做一类水饺,**工厂方法模式(Factory Method Pattern)**应运而生。
直接上代码:
- 建立我们的大工厂
public interface IDumplingFactory {
/**
* 启动水饺流水线
*
* @return 指定水饺的流水线
*/
IDumplings create();
}
- 建立各种水饺流水线-举个白菜例子,其他类似
public class CabbageDumplingFactory implements IDumplingFactory {
@Override
public IDumplings create() {
return new CabbageDumpling();
}
}
- 启动我们的流水线,制作水饺
public static void main(String[] args) {
//开启白菜水饺流水线
CabbageDumplingFactory cabbageDumplingFactory = new CabbageDumplingFactory();
//开启芹菜水饺流水线
CeleryDumplingFactory celeryDumplingFactory = new CeleryDumplingFactory();
//开始制作白菜水饺
cabbageDumplingFactory.create().make();
//开始制作芹菜水饺
celeryDumplingFactory.create().make();
}
这样,我们在上新品类的时候,只需要新增流水线即可,而无需过多关注产品创建的细节,符合开闭原则,但是工厂方法模式也存在弊端,会导致流水线(类)越来越多。
抽象工厂模式
我们在生产的过程当中,流程都是一样的,比如水饺的生产流程就是1.做皮,2.调馅,3.制作打包。但是这个过程中,做皮是一样的,后续的流程也是不让你随意变动的,抽象工厂模式就为解决此类问题而来,话不多说,上代码。
- 约定好后续具体步骤
/**
* <p>IStuffing</p>
* 调馅的过程
*
* @author TimeRoar-Wang Ziming
* @date 2021/10/29 22:42
*/
public interface IStuffing {
/**
* 调配
*/
void deploy();
}
/**
* <p>IPackage</p>
* 制作打包的过程
*
* @author TimeRoar-Wang Ziming
* @date 2021/10/29 22:45
*/
public interface IPackage {
/**
* 水饺包装盒
*/
void box();
}
- 提供我们的核心技术,以此为基础开始制作
public abstract class KernelDumplingFactory {
/**
* 这里用了上等秘方老面,统一制作
* */
public void makeWrapper() {
System.out.println("制作出来水饺皮");
}
/** 调馅 */
public abstract IStuffing createStuffing();
/** 打包 */
public abstract IPackage createBox();
}
- 对每个步骤的方法实现具体操作-以芹菜举例
public class CeleryStuffing implements IStuffing{
@Override
public void deploy() {
System.out.println("制作芹菜馅");
}
}
//打包方法
public class CeleryBox implements IPackage{
@Override
public void box() {
System.out.println("芹菜水饺打包");
}
}
- 开始流水线操作
public static void main(String[] args) {
//开启白菜水饺流水线
CabbageFactory cabbageFactory = new CabbageFactory();
//做皮
cabbageFactory.makeWrapper();
//调馅
cabbageFactory.createStuffing();
//打包
cabbageFactory.createBox();
}
由此,一条完整的流水线就制作成功了,整个制作流程抽象工厂模式清晰的描述出来,但是依旧存在缺点,如果我想在流水线中加入一个环节,比如,把水饺做成形状加入进去,全部流水线也都需要调整,完全不符合开闭原则。
结言
至此,三种工厂模式介绍完了,都有各自的优缺点,实际运用中依据自己项目实际情况选择应用,有时候开闭原则不用太过在意遵循,迭代周期一年两年有何不可。文章中提到的源码。可访问我的 github仓库 进行参考。不足之处,也请留言指出