0x02. 23 种设计模式
23种设计模式(完整分类+核心解读)
23种设计模式是《设计模式:可复用面向对象软件的基础》(俗称“四人帮/Gof”)提出的经典分类,核心是解耦、复用、可扩展,按功能分为3大类:创建型(5种)、结构型(7种)、行为型(11种),适配几乎所有面向对象开发场景。
一、 创建型模式(5种)
核心:封装对象的创建过程,不直接new对象,让创建逻辑与业务逻辑分离,灵活控制对象实例化。
适合场景:对象创建复杂、需要统一管控、要隐藏创建细节时。
- 单例模式(Singleton)
- 核心:保证一个类全局只有一个实例,并提供全局访问点。
- 场景:全局配置、数据库连接池、日志对象。
- 注意:线程安全(饿汉式/懒汉式/双重校验锁)、防止反射破坏。
- 工厂方法模式(Factory Method)
- 核心:定义创建对象的接口,让子类决定具体创建哪个类,把创建延迟到子类。
- 场景:日志框架(日志可以是文件/控制台/数据库,子类决定)、不同数据库驱动创建。
- 优点:新增产品只需加子类,符合开闭原则。
- 抽象工厂模式(Abstract Factory)
- 核心:提供一个接口,创建一系列相关/依赖对象,无需指定具体类(生产“产品族”)。
- 场景:系统风格切换(Windows/Mac风格的按钮、输入框)、数据库配套组件(连接+事务+查询)。
- 区别于工厂方法:工厂方法造“单一产品”,抽象工厂造“一组配套产品”。
- 建造者模式(Builder)
- 核心:将复杂对象的构建与表示分离,相同构建过程能创建不同表示。
- 场景:复杂对象创建(比如自定义电脑:CPU+内存+硬盘+显卡,组合不同配件)、HTTP请求构建。
- 优点:分步构建、灵活控制细节,避免多参数构造器。
- 原型模式(Prototype)
- 核心:通过复制已有实例(原型) 创建新对象,无需重新初始化,效率更高。
- 场景:对象创建成本高(比如大数据对象、复杂初始化对象)、需要批量生成相似对象。
- 关键:深克隆/浅克隆(浅克隆复制引用,深克隆复制对象本身)。
二、 结构型模式(7种)
核心:处理类或对象的组合关系,优化类结构、提高复用性,让结构更灵活且满足需求。
适合场景:需要组合已有类/对象实现新功能、解决类之间耦合、优化复杂结构时。
- 适配器模式(Adapter)
- 核心:将一个类的接口转换成客户端期望的另一个接口,让不兼容的类能一起工作(“转换器”)。
- 场景:新旧系统兼容(比如老接口返回List,新系统需要Set)、第三方组件适配。
- 分类:类适配器(继承)、对象适配器(组合,更推荐)。
- 桥接模式(Bridge)
- 核心:将抽象部分与实现部分分离,让两者可以独立变化,解耦抽象和实现。
- 场景:多维度变化的场景(比如“形状”和“颜色”:形状有圆形/方形,颜色有红/蓝,两者独立扩展)、消息通知(通知方式:短信/邮件;通知类型:普通/紧急)。
- 优点:避免类爆炸(不用创建圆形红、圆形蓝、方形红...等大量子类)。
- 组合模式(Composite)
- 核心:将对象组合成树形结构,表示“部分-整体”关系,让客户端统一处理单个对象和组合对象。
- 场景:树形结构场景(文件夹+文件、菜单+子菜单+菜单项、部门组织架构)。
- 关键:叶子节点(无子节点,如文件)和组合节点(有子节点,如文件夹)实现统一接口。
- 装饰器模式(Decorator)
- 核心:动态给对象添加额外功能,不改变原类结构,比继承更灵活(“锦上添花”)。
- 场景:功能动态扩展(比如咖啡:基础咖啡+加奶+加糖+加冰,自由组合)、IO流包装(Java中BufferedReader装饰InputStream)。
- 区别于继承:继承是静态扩展,装饰器是动态扩展,可叠加。
- 外观模式(Facade)
- 核心:为复杂子系统提供统一的对外接口,简化客户端调用,隐藏子系统细节。
- 场景:复杂系统调用(比如电商下单:需要调用库存、支付、物流子系统,外观类封装成一个“下单”方法)、框架对外API。
- 优点:降低客户端与子系统的耦合,简化使用。
- 享元模式(Flyweight)
- 核心:复用内存中已存在的对象,减少创建大量相似对象的内存消耗,共享“细粒度对象”。
- 场景:大量重复对象场景(比如围棋棋子、验证码字体、池化技术)。
- 关键:区分内部状态(共享,如棋子颜色)和外部状态(不共享,如棋子位置)。
- 代理模式(Proxy)
- 核心:为其他对象提供一个代理对象,控制对原对象的访问,可附加额外逻辑。
- 场景:权限控制、日志记录、懒加载、远程调用(RPC)。
- 分类:静态代理(编译期确定)、动态代理(运行时生成,如Java的JDK代理、CGLIB)。
三、 行为型模式(11种)
核心:处理类或对象之间的交互与职责分配,规范通信方式,让交互更清晰、职责更明确,提高灵活性。
适合场景:需要定义对象间通信规则、分配职责、处理算法变化时。
- 责任链模式(Chain of Responsibility)
- 核心:将请求的发送者和接收者解耦,多个接收者连成链,请求沿链传递,直到被处理。
- 场景:多级审批(请假:组长→部门经理→总监)、过滤器链(Web请求过滤)、异常处理链。
- 优点:新增处理器只需加节点,无需修改原有链。
- 命令模式(Command)
- 核心:将请求封装成独立的命令对象,包含接收者和执行逻辑,支持请求的排队、撤销、重做。
- 场景:按钮点击事件(点击按钮=执行对应命令)、任务队列、撤销操作(比如编辑器撤回)。
- 角色:命令(接口)、具体命令、调用者(触发命令)、接收者(执行实际逻辑)。
- 解释器模式(Interpreter)
- 核心:定义语言的文法规则,并构建解释器来解释语言中的句子。
- 场景:简单语法解析(比如表达式计算1+2*3、正则表达式解析、配置文件解析)、自定义小型DSL。
- 缺点:文法复杂时类会爆炸,只适合简单场景。
- 迭代器模式(Iterator)
- 核心:提供一种方法顺序访问集合对象的元素,无需暴露集合的内部结构。
- 场景:遍历集合(比如Java的Iterator、Python的for循环迭代)、统一不同集合的遍历方式。
- 优点:遍历和集合解耦,新增集合只需实现迭代器接口。
- 中介者模式(Mediator)
- 核心:定义一个中介对象,封装多个对象之间的交互,让对象无需直接通信,降低耦合。
- 场景:多对象复杂交互(比如聊天室(中介):用户不用直接发消息给对方,发给聊天室转发)、GUI组件交互。
- 优点:减少对象间的直接依赖,交互逻辑集中管理。
- 备忘录模式(Memento)
- 核心:在不破坏封装的前提下,保存对象的内部状态,以便后续恢复(“快照”)。
- 场景:数据备份与恢复(比如编辑器保存草稿、游戏存档、撤销操作)。
- 角色:原发器(保存状态)、备忘录(存储状态)、管理者(管理备忘录,不修改)。
- 观察者模式(Observer)
- 核心:定义一对多的依赖关系,当一个对象(被观察者)状态变化,所有依赖它的对象(观察者)自动收到通知并更新。
- 场景:发布-订阅模型(比如公众号推送、消息通知、事件监听)、数据绑定。
- 分类:推模型(被观察者主动推数据)、拉模型(观察者主动拉数据)。
- 状态模式(State)
- 核心:将对象的状态封装成独立的状态类,对象状态变化时,切换对应的状态类,让行为随状态改变而改变。
- 场景:对象有多种状态且行为随状态变化(比如订单状态:待付款→待发货→待收货→完成)、电梯运行状态。
- 区别于条件判断:用状态类替代if-else/switch,更清晰、易扩展。
- 策略模式(Strategy)
- 核心:定义一系列算法,将每个算法封装成独立类,让它们可以互相替换,算法变化不影响使用算法的客户端。
- 场景:算法灵活切换(比如排序算法:冒泡/快排/归并、支付方式:微信/支付宝/银行卡)。
- 优点:避免多重条件判断,算法可复用、易扩展。
- 模板方法模式(Template Method)
- 核心:在父类中定义算法的骨架(模板),将可变的步骤延迟到子类实现,固定流程、灵活细节。
- 场景:流程固定但细节不同(比如泡茶/泡咖啡:流程都是“烧水→放原料→冲泡→倒出”,原料不同)、框架核心流程(比如Spring的Bean生命周期)。
- 关键:父类控制流程,子类实现细节,符合“开闭原则”。
- 访问者模式(Visitor)
- 核心:将数据结构和数据操作分离,新增操作时无需修改数据结构,只需加访问者类。
- 场景:数据结构稳定、操作频繁变化(比如报表生成:同一批数据,生成Excel/Word/PDF报表,数据不变,操作变化)。
- 缺点:数据结构变化时,所有访问者都要修改,适合结构稳定的场景。
四、 关键补充(开发必知)
1. 设计模式的核心原则(底层支撑)
所有设计模式都围绕SOLID原则展开,是判断是否用对模式的标准:
- 单一职责:一个类只做一件事
- 开闭原则:对扩展开放,对修改关闭(核心)
- 里氏替换:子类可替换父类且不影响功能
- 接口隔离:接口要细化,不依赖不需要的方法
- 依赖倒置:依赖抽象,不依赖具体实现
2. 常用模式优先级(开发高频)
不用死记所有模式,优先掌握这些高频款即可覆盖80%场景:
- 必学:单例、工厂方法、装饰器、代理、观察者、策略、模板方法
- 常用:建造者、适配器、外观、责任链、状态
- 小众:抽象工厂、桥接、组合、享元、原型、解释器、中介者、备忘录、访问者
3. 避坑提醒
- 不要过度使用:简单场景用简单代码,不用强行套模式(比如单例不要滥用,非全局唯一没必要)
- 优先组合,少用继承:设计模式大多推荐“组合/聚合”,比继承更灵活
- 模式是工具,不是规范:核心是解决问题,不是为了用模式而用模式