Article
创建型设计模式总结
· 5 分钟阅读
单例、工厂、抽象工厂、建造者、原型——这五个模式都被归进”创建型”,但它们解决的问题并不一样。五个一起背下来,遇到具体问题时反而挑不出来。
这篇不重复各自的实现(每个模式都有单独一篇),只做一件事:把”创建对象”这件事拆成几种不同的麻烦,看每种该找谁。
创建对象的代码,通常是这样变难维护的
第一种:调用方不该知道具体用哪个类。 业务代码里散落着 new,换一个实现就要翻遍所有调用点。这时候要的不是”更好的 new”,而是把创建这个动作本身挪走——这是工厂。
第二种:这个对象要分好几步才装得起来。 构造函数参数列表越来越长,还都是可选的,调用方开始靠位置记忆参数含义。这时候需要把”怎么装”和”装成什么”分开——这是建造者。
第三种:全局只该有一个,或者复制比新建划算。 前者是单例,后者是原型。这两个容易和前面混,但它们的出发点不是”解耦创建过程”,而是”控制实例的数量和来源”。
按麻烦排的对照表
| 你的麻烦 | 该用的模式 | 它把什么挪走了 | 代价 |
|---|---|---|---|
| 调用方不该知道具体类 | 工厂 | 把 new 收进一个创建入口 | 多一层间接,类数量增加 |
| 要成套地换产品系列 | 抽象工厂 | 一族产品的创建集中到一个接口 | 增加新的产品种类很别扭 |
| 构造步骤多、组合多变 | 建造者 | 把构建过程与最终表示分离 | 多写一个建造者类,简单对象上显得啰嗦 |
| 全局只能有一个实例 | 单例 | 把构造封起来,只留取实例的入口 | 依赖被藏进全局,测试难并行 |
| 新建比复制贵 | 原型 | 用克隆代替构造 | 深拷贝的边界要自己处理 |
最容易混的两组
工厂 vs 抽象工厂。 工厂解决的是”用哪一个类”,一次决定一个产品;抽象工厂解决的是”用哪一套类”,一次决定一族产品。判断方法很简单:如果新增一个产品种类时你希望只加一个类,用工厂;如果新增一个产品系列时你希望只加一个类,用抽象工厂。反过来加,都会别扭。
单例 vs 原型。 两者都在控制实例的来源,但方向相反:单例把入口收到唯一一处,原型把入口放开成”从现有对象复制”。前者怕的是多,后者怕的是贵。一个模块里同时用这两个模式,通常说明实例的生命周期没想清楚。
逐个展开
- 单例模式:全局只有一个实例,代价是什么 —— 饿汉、懒汉、双重检查锁三种写法,以及它在前端项目里真正出现的位置。
- 工厂模式:把 new 收进一个入口 —— 从简单工厂讲到抽象工厂,含两套完整示例。
- 建造者模式:把装配过程拆成步骤 —— 什么时候值得多写一个建造者类。
- 原型模式:复制比新建划算时 —— 克隆的适用边界与深拷贝的坑。
选哪个模式,最终取决于你把哪一部分当成了变化点。想清楚这一点,上面这张表其实可以不看。
Keep Reading