登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
博客
发1篇日志+1圆
记录
发1条记录+2圆币
发帖说明
VIP申请
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
VIP申请
VIP网盘
网盘
联系我们
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
设计模式:简单工厂、工厂方法与抽象工厂 ...
设计模式:简单工厂、工厂方法与抽象工厂
[ 复制链接 ]
挫莉虻
2025-6-20 07:58:19
导航
1为什么要使用工厂模式?
2简单工厂
3工厂方法
3抽象工厂
4后记
1 为什么要使用工厂模式?
解耦
工厂模式的核心目的是将对象的创建与使用分离,先说对象的创建,我们习惯于在构造函数中进行一系列对象的初始化甚至逻辑处理,虽然这在开发中很常见,但如果仔细推敲,会发现其实并不符合常理。如果把汽车的发动机当作一个对象,设计图纸当作构造函数的参数,我们传入参数,然后发动机自己把自己生产出来了。是的,发动机自己生产了自己,是不是感觉有些怪异?但这确实是软件中的大部分情形,其实现实生活中的场景更符合逻辑,把图纸送到发动机生产工厂,由工厂完成发动机的生产制造。在软件开发中,大多数简单对象,并不需要使用工厂,但当一个对象的构造过程相对复杂、易变时,就需要考虑使用工厂将对象的创建过程解耦了。
再说对象的使用,在简单的小型项目中,直接使用new来获取对象简便快捷,并没有问题。但当项目具有一定规模,需要统一考虑扩展性(使用一个对象替换另一个对象),需要统一管理多个对象的创建过程、生命周期、依赖关系时,工厂就大有用武之地了。
抽象
解释一下抽象的概念,在软件设计中,抽象是为解耦和扩展而生的。举个例子,我们打开电脑机箱找到主板上的南北桥芯片,可以看到它们是完全焊接在主板上的,这种不可替换的设计是高耦合不可扩展的。我们再找到内存条,发现它们可以拆卸并更换为其它品牌,这种可替换的设计即为可扩展。再稍深入思考一下,主板上的内存条为什么能安装不同的品牌?原因是有相关技术标准,比如长宽尺寸,针脚数量,通信标准等,不同的内存条厂商,只要遵循标准生产出来的内存条就能安装到同一块主板上。在软件开发中,让主板支持不同厂商内存条的能力称之为主板具备可扩展性,定义内存条接口标准称之为抽象,根据标准生产主板和内存条称之为面向抽象编程(面向接口编程)。
在软件设计中,只要是工厂模式,不论简单工厂、工厂方法、还是抽象工厂,生产构造出来的都是抽象对象,而非具体对象。这条规则非常重要,我们在小型项目中,效率优先,可以直接new出来具体的对象使用,但即然使用了工厂模式,说明项目具有了一定的复杂程度和规模,此时就应该统一考虑可扩展性了。
可测试性
做过单元测试的小伙伴应该深有体会,越是封闭的对象越难以测试。这很容易理解,要对一个对象进行测试,就需要从外部对它注入各种条件,然后观察它的反应,如果条件都注入不进去,何来的反应呢?构造函数对测试而言,天生就是一个无法测试的封闭黑盒,而工厂模式把这个黑盒从对象中解耦了出来,从而允许测试条件的注入。
2 简单工厂
在一个工厂中,通过向静态方法传递不同的参数,生产并返回不同的产品,即简单工厂,又形象的称之为静态工厂方法(Static Factory Method),示例代码如下:
// 抽象产品
public interface ICellphone
{ }
// 具体产品
public class Xiaomi1Cellphone : ICellphone
{ }
public class Xiaomi2Cellphone : ICellphone
{ }
// 小米1和小米2是早期的小米手机型号
public enum CellphoneBrand
{
Xiaomi1,
Xiaomi2
}
// 简单工厂
public class CellphoneFactory
{
// 通过不同的参数构造并返回不同的对象
public static ICellphone Build(CellphoneBrand brand)
{
switch (brand)
{
case CellphoneBrand.Xiaomi1:
return new Xiaomi1Cellphone();
case CellphoneBrand.Xiaomi2:
return new Xiaomi2Cellphone();
// 缺点:当产品扩展时存在修改,不符合开闭原则
// ...
default:
return null;
}
}
}
复制代码
1994年,Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides四位合著了《设计模式-可复用面向对象软软件的基础》,书中总结了23种常用的设计模式,后来成为了大名鼎鼎的GoF23(四人帮:Gang of Four)。
简单工厂虽然不在GoF23当中,但实际开发中也较为常见,它的优点是非常简单,缺点是当产品扩展时,需要修改工厂中的代码,不符合“开闭原则”。
3 工厂方法
在介绍工厂方法模式前,先简单介绍一下“开闭原则”,开闭原则在上世纪80年代就被总结了出来,其核心思想是对修改关闭,对扩展开放。对修改关闭指的是应避免修改已存在的代码,因为这部分代码是经过测试的稳定代码,任何修改都可能引入新的BUG;对扩展开放指的是应允许增加新功能,因为软件存在的价值就是不断满足用户新的需求。开闭原则看似简单,实则包含了众多软件设计思想与实现细节,整个“SOLID原则”几乎都是围绕它展开的,后续专门写一篇文章介绍开闭原则,此处就不作详述了。
工厂方法模式的核心思想是每增加一种产品,就对应的增加一个工厂,为了贯彻这个思路,方便的为新增产品匹配工厂,它对工厂也进行了抽象,示例代码如下:
// 抽象产品
public interface ICellphone
{ }
// 具体产品
public class XiaomiCellphone : ICellphone
{ }
public class RedmiCellphone : ICellphone
{ }
// 抽象工厂
public interface ICellphoneFactory
{
ICellphone Build();
}
// 具体工厂
public class XiaomiCellphoneFactory : ICellphoneFactory
{
public ICellphone Build()
{
return new XiaomiCellphone();
}
}
public class RedmiCellphoneFactory : ICellphoneFactory
{
public ICellphone Build()
{
return new RedmiCellphone();
}
}
复制代码
工厂方法符合开闭原则,但它也存在缺陷:一个工厂只能生产一种产品,工厂数量会随着产品数量的增加而不断增加。
4 抽象工厂
在具有一定规模的实际项目中,对象通常不会孤立的出现,而是以系列的方式出现,比如小米和红米,两个品牌下不会只有一款产品,而会有一系列产品:手机、电视、电脑、智能音箱、扫地机器人等等。抽象工厂模式专为生产一系列商品而设计,它解决了工厂方法中工厂数量随着产品数量不断增加的弊端,也更贴合实际的项目场景,示例代码如下:
// 抽象产品
public interface ICellphone
{ }
public interface ITelevision
{ }
// 具体产品
public class XiaomiCellphone : ICellphone
{ }
public class RedmiCellphone : ICellphone
{ }
public class XiaomiTelevision : ITelevision
{ }
public class RedmiTelevision : ITelevision
{ }
// 抽象工厂
public interface IFactory
{
ICellphone BuildCellphone();
ITelevision BuildTelevision();
}
// 具体工厂,生产一个系列的产品
public class XiaomiFactory : IFactory
{
public ICellphone BuildCellphone()
{
return new XiaomiCellphone();
}
public ITelevision BuildTelevision()
{
return new XiaomiTelevision();
}
}
public class RedmiFactory
{
public ICellphone BuildCellphone()
{
return new RedmiCellphone();
}
public ITelevision BuildTelevision()
{
return new RedmiTelevision();
}
}
复制代码
5 后记
很早之前就想将GoF23中的设计模式以这种图、文、代码的方式整理成文,一直拖延直到最近注册了心仪的域名,博客园的这个20年前的账号也重获新生,终于开始将软件开发这些年的一些经验整理成文。后续会陆续补充完整GoF23,敬请关注。
本文同步发步于个人站点:wubayue.com
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
工厂
设计模式
简单
方法
抽象
相关帖子
向量索引的混合查询方法,你选对了吗?
Java MCP 的鉴权?好简单的啦
static 静态方法的特点和作用
简单4步,快速搭建数字人实时视频通话功能
指数估值-A股主流指数的估值方法
Linux性能分析工具和方法
关于 01 背包问题的简单解释,理解状态转移与继承的相似性
设计模式之单例模式
ORA-01720 错误及解决方法
将 PDF 转换为 TIFF 图片:简单有效的 Java 教程
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
科技
向量索引的混合查询方法,你选对了吗?
0
191
后彼
2025-08-19
业界
Java MCP 的鉴权?好简单的啦
0
581
泡市
2025-08-19
业界
static 静态方法的特点和作用
0
840
拼匍弦
2025-08-20
业界
简单4步,快速搭建数字人实时视频通话功能
0
174
扈季雅
2025-08-25
安全
指数估值-A股主流指数的估值方法
0
997
全叶农
2025-08-25
业界
Linux性能分析工具和方法
0
114
眸胝
2025-09-01
业界
关于 01 背包问题的简单解释,理解状态转移与继承的相似性
0
385
烯八
2025-09-01
安全
设计模式之单例模式
0
60
颖顿庐
2025-09-03
安全
ORA-01720 错误及解决方法
0
763
万妙音
2025-09-04
安全
将 PDF 转换为 TIFF 图片:简单有效的 Java 教程
0
600
豺独
2025-09-04
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
浏览过的版块
代码
科技
签约作者
程序园优秀签约作者
发帖
挫莉虻
2025-6-20 07:58:19
关注
0
粉丝关注
16
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9984
黎瑞芝
9990
杭环
9988
4
凶契帽
9988
5
氛疵
9988
6
猷咎
9986
7
接快背
9986
8
里豳朝
9986
9
肿圬后
9986
10
段干叶农
9986
查看更多