工厂模式的演化与关系(简单工厂、工厂方法、抽象工厂)

231 阅读5分钟

学习工厂模式的过程中,让我产生疑惑较多的是简单工厂、工厂方法、抽象工厂三者的关系

甚至在阅读的教程中,遇到有把工厂Function升级为工厂Class的简单工厂,就将其作为了工厂方法(其实本质还是简单工厂),然后把工厂方法作为了抽象工厂来讲
导致差点以为工厂方法作为简单工厂到抽象工厂的过渡并无卵用

因此本文想借由一个模拟需求,梳理下这三者的演化过程

简单工厂

假设你在写一款模拟人生游戏,需要为游戏中的各种商店写一些基本操作,那么首先会设计一个 Store 的抽象类,再设计出各种继承此类的 ClothesStore、FlowerStore、RiceStore、BookStore...

image.png

随着各式各样的商店类型越来越多,你逐渐记不起几天前定义的“饭店类”到底叫 RiceStore 还是 Restaurant,只得中断正文思泉涌敲打代码逻辑的手指,到触控板上挪动光标,查找到当事店确认名称 😥

确认是 Restaurant 后,你又一如其它创建场景需要先写个 if 判断玩家有无足够的金钱与技能点后,才允许成功创建并继续书写后面的逻辑
你想,这明明是创建商店的统一逻辑,得想办法把它们封装起来,却苦苦找不到可用统一提取到的位置 😰

正当你为此感到烦恼时,简单工厂模式出现了,于是经过一番学习与折腾,你有了如下的结构:

image.png

组成

  • 抽象产品(Store)
  • 具体产品(FlowerStore、ClotherStore...)
  • 工厂类(Factory)

优点

  • 无需知道各个具体产品的类名,只需要工厂类的一个参数,就可以获取到所需的对象 (管你 RiceStore 还是 Restaurant)
  • 无需知道其创建的具体细节 (再也不用先写个 if 判断玩家余额了)

缺点

只能在对象的创建逻辑不复杂时使用,且不符合开闭原则

工厂方法

随着游戏的逐渐复杂,产品经理让你在创建商店之前加入了更多先决条件:

开饭店需要玩家持有食品经营许可证、开书店需要有出版物经营许可证、开花店需要玩家先进修花卉养护技能、开服装店不能加入BCI协会...

为了满足需求,你只能往创建商店的 Factory 类中不断加入各种商店类型的判断逻辑,createStore 方法越来越庞大,对于有的商店来说也多出了不必要的判断 😥

并且随着每一次新商店类型的增加,createStore 也逐渐复杂,还必须确保原有的代码逻辑不会受到新增的影响 😰

问题不大,你想,是时候把不同商店的创建逻辑分离了
于是,工厂方法应运而生,你的结构进化成了这样:

image.png

组成

  • 抽象产品(Store)
  • 具体产品(FlowerStore、ClotherStore...)
  • 抽象工厂(AbstractFactory)
  • 具体工厂(FlowerFactory、ClotherFactory...)

优点

  • 将创建对象的具体逻辑落地到子类(具体工厂类)中实现 (可以有针对性地检测经营许可证、技能点等)
  • 增加新产品时,无需在原工厂类上进行修改,符合开闭原则 (不用担心新增商店类型的逻辑可能对原有的造成影响了)

缺点

每次添加新产品时,需要同时编写新的具体产品类和与之对应的具体工厂类
系统中类的数量会成对增加,复杂性也随之增加

抽象工厂

“这都1202年了”,产品经理又来说道,“电商随处可见的现在,咱的游戏是不是该顺应潮流,把开网店也作为玩家的一种职业选择呢?”

你想,似乎是个挺新颖的游戏功能
就是比较麻烦,之前出现过的很多商店类型都要复制粘贴一下了:

image.png

“啪!”
技术主管忽然从身后给了你的脑袋一巴掌
“什么玩意儿,这不多此一举吗,明明有基本一样类型的工厂,为什么不把它们分个类合并了呢”

啊!恍然大悟,一顿骚操作后终于把结构确定下来了:

image.png

组成

同工厂方法

优点

  • 当抽象产品类有多个时(Store、EStore),将具体工厂类再分类,以减少具体工厂类的数量 (牺牲了部分开闭原则来减少繁乱的类数量)

半开闭原则

  • 当增加新产品族(花店、饭店、服装店)时,只需要增加新的具体产品和具体工厂,无须修改原有代码,符合开闭原则
  • 当增加新产品等级结构(实体店、网店)时,需要增加新的抽象产品和具体产品,并修改抽象工厂和具体工厂的内容,不符合开闭原则

三种模式的关系

演化

抽象工厂模式中:
if 只存在一个产品等级结构,即每一个具体工厂类只创建一个具体产品
then 抽象工厂模式 退化为 工厂方法模式

工厂方法模式中:
if 抽象工厂与具体工厂合并,只提供一个统一的工厂来创建具体产品
then 工厂方法模式 退化为 简单工厂模式

正向演化:
image.png

简单定义的对比