是一种面向对象设计模式,定义了 工厂 的概念,软件设计时抽象产品派生出产品子类,具体的产品实例由 工厂 创建,用户从 工厂 申请需要的产品实例来使用。
简单工厂的概念并不存在于23种设计模式之中,学习的过程中发现其实现原理有助于理解本文后面两种设计模式。这里就列举出来。
其实现原理是,先抽象出产品的基类,然后由基类派生出各种产品子类。工厂 仅需要设计业务,由输入参数来确定创建哪种产品实例^ 注1。
假设一个场景: 某手机厂商旗下有Mate、Nova和P等品牌,不同的品牌功能相同但参数有所差异,工厂拥有生产所有品牌手机的能力。当Mate品牌发布新机,工厂需要生产Mate品牌;类似的,当其他品牌发布新机,工厂也需要生产其他品牌。那么从面向对象设计的角度,如何将此场景设计出来呢?
解决: 首先将类定义出来,涉及到Mate、Nova、P和工厂类。工厂的接口返回手机的实例,那么问题来了,从软件角度来思考,工厂的一个接口只能返回一种类的实例,如何让一个接口返回多个不同类的实例呢?C++基类虚函数可以解决这个问题[^注2]。因此将Mate、Nova和P抽象出一个基类CPhone,工厂接口类型指定为CPhone *。加入逻辑判断,达到不同的参数返回不同的手机实例效果。
类图
简单工厂
使用方法: 当需要生产某个品牌手机时,只需要在工厂方法getPhoneInstance指定product即可获取到某品牌实例。
缺点:
由于简单工厂的缺点是不可忽视的,因此对简单工厂进行优化从而产生 工厂方法 的概念。从简单方法的类图中可以发现,工厂方法getPhoneInstance需要优化。
解决: 由多个工厂子类替换掉参数的做法。将工厂类派生出多个工厂子类,一个工厂子类对应一个产品子类。如此一来,增加一个产品时,仅需要增加一个工厂子类即可,不需要对之前的逻辑进行修改。
类图:
工厂方法
使用方法: 当需要生产某种品牌时,用户只需要由new对应的工厂子类实例,由getPhoneInstance获取此品牌实例。若增加新品牌,需要工厂派生新的工厂子类,对应的产品派生出新的产品子类,由新的工厂实例getPhoneInstance返回新的产品实例即可。
缺点:
工厂方法多用于同一类型的产品生产,即仅存在一个抽象产品基类。假设业务需要,工厂要增加新产品(Watch)。此时 工厂方法 的设计无法满足需求,由此又提出了抽象工厂的概念。
解决方法: 新增产品基类CWatch派生出产品子类CHwGt2、CHwGt2Pro,同时在工厂基类中增加获取该子类实例的接口。如此一来,每个工厂都具备生产CPhone和CWatch的能力。
类图:
抽象工厂
使用方法: 与工厂方法类似,先new出对应的工厂子类实例,然后调用getPhoneInstance和getWatchInstance获取对应的产品实例。
缺点:
[^ 注1]: 一个方法返回不同的实例。
[^ 注2]: C++继承中可以将基类虚函数的重写,基类类型会调用子类重写的虚函数。
[^ 注3]: 开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。
用心感悟,认真记录,写好每一篇文章,分享每一框干货。
更多文章内容包括但不限于C/C++、Linux、开发常用神器等,可进入开源519公众号聊天界面回复“文章目录” 或者 菜单栏选择“文章目录”查看。