【设计模式】(core)
2022年1月10日...大约 10 分钟
【设计模式】(core)
⚽设计模式学习笔记:基于优秀的参考书籍进行学习,结合业务开发探索过程的问题思考,整理个人学习笔记,在后续的学习中相应迭代案例分析和场景应用
核心学习思路:先理解设计模式核心概念和应用场景,先构建一个最简单的demo场景进行设计理解,随后进一步结合实际的业务场景进行扩展理解分析
🚀学习进度(结合业务场景理解设计模式应用)
- 创建型:对象创建&实例化(提供创建对象的机制)
- [x] 工厂模式:抽象工厂、工厂方法
- [x] Builder构造器模式
- [x] 单例模式:单例模式、注册器模式(单例模式的特例)
- 结构型:将对象和类组装成较大的结构,并保持高效和灵活
- [x] 适配器模式
- [x] 装饰器模式
- [x] 门面模式
- [x] 代理模式
- [x] 桥接模式
- 行为型:负责对象之间的交互和职责委派
- [x] 观察者模式
- [x] 策略模式
- [x] 模板方法模式
- [x] 责任链模式
- [x] 状态模式
✨学习参考书籍:
- 初识设计模式:菜鸟设计模式-RUNOOB.COM
- 图解设计模式
- 🎉🎉重学Java模式(小傅哥):项目场景应用案例,基于业务场景进一步掌握设计模式场景应用
- 图⽂设计模式资料:REFACTORING.GURU
设计模式核心概念
1.基本概念
设计模式是设计过程中可以反复使用的、可以解决特定问题的设计方法。通过了解一些设计模式的概念,去构建良好的代码结构,提升全局把控能力
2.六⼤基本原则
设计模式遵循六大基本原则,这些原则帮助开发者设计出更灵活、可维护的系统。通过遵循这些原则,可以减少代码耦合,提高系统的可扩展性和可维护性
- 单⼀职责( ⼀个类和⽅法只做⼀件事 )
- ⾥⽒替换( 多态,⼦类可扩展⽗类 )
- 依赖倒置( 细节依赖抽象,下层依赖上层 )
- 接⼝隔离( 建⽴单⼀接⼝ )
- 迪⽶特原则( 最少知道,降低耦合 )
- 开闭原则( 抽象架构,扩展实现 )
① 单一职责(SRP)
定义:一个类应该只有一个职责,即只有一个引起它变化的原因
场景:电商系统中的订单处理
- 问题:订单处理涉及到订单、支付、物流等多个核心环节,如果订单类同时负责订单创建、支付处理和物流跟踪,修改支付逻辑可能会影响其他功能且功能耦合
- 解决方案:将订单类拆分为三个类:
OrderCreation
、PaymentProcessing
和ShippingTracking
,每个类只负责一个功能
② 开闭原则(OCP)
定义:软件实体应对扩展开放,对修改关闭
场景:支付系统支持多种支付方式
- 问题:每次新增支付方式(如支付宝)都需要修改现有代码
- 解决方案:定义一个
PaymentStrategy
接口,每种支付方式实现该接口。新增支付方式时只需添加新实现类,无需修改现有代码
类似引入策略模式,支持不同的支付策略算法
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
// 信用卡支付逻辑
}
}
class AlipayPayment implements PaymentStrategy {
public void pay(int amount) {
// 支付宝支付逻辑
}
}
③ 里氏替换(LSP)
定义:子类应能替换父类,且不影响程序的正确性
场景:图形绘制系统
- 问题:如果
Rectangle
是Square
的父类,Square
重写了setWidth
和setHeight
方法,导致行为不一致 - 解决方案:避免继承关系,或确保子类不改变父类的行为
class Rectangle {
void setWidth(int width) { /* ... */ }
void setHeight(int height) { /* ... */ }
}
class Square extends Rectangle {
void setWidth(int width) {
super.setWidth(width);
super.setHeight(width); // 违反 LSP
}
}
④ 接口隔离(ISP)
定义:客户端不应依赖不需要的接口
场景:多功能打印机
- 问题:如果
Printer
接口包含打印、扫描和传真方法,但某些打印机只能打印,实现类被迫实现不需要的方法 - 解决方案:将接口拆分为
Printer
、Scanner
和FaxMachine
,客户端只需依赖所需接口
interface Printer {
void print();
}
interface Scanner {
void scan();
}
class SimplePrinter implements Printer {
public void print() {
// 打印逻辑
}
}
⑤ 依赖倒置(DIP)
定义:高层模块不应依赖低层模块,两者都应依赖抽象
场景:通知系统
- 问题:高层模块
NotificationService
直接依赖EmailService
,导致难以替换为其他通知方式 - 解决方案:引入
MessageService
接口,EmailService
和SMSService
实现该接口,NotificationService
依赖MessageService
interface MessageService {
void sendMessage(String message);
}
class EmailService implements MessageService {
public void sendMessage(String message) {
// 发送邮件逻辑
}
}
class NotificationService {
private MessageService messageService;
NotificationService(MessageService messageService) {
this.messageService = messageService;
}
void sendNotification(String message) {
messageService.sendMessage(message);
}
}
⑥ 迪米特法则(LoD)
定义:一个对象应尽可能少地了解其他对象
场景:公司员工管理系统
- 问题:
Department
类直接访问Employee
的详细信息,导致耦合度过高 - 解决方案:
Department
只与Employee
交互,不直接访问其内部细节
class Employee {
private String name;
private String address;
String getName() {
return name;
}
}
class Department {
private List<Employee> employees;
void printEmployeeNames() {
for (Employee employee : employees) {
System.out.println(employee.getName());
}
}
}
设计模式分类
IO 流使用的是装饰者模式、按钮监听观察者模式、forEach 遍历List、TreeSet 使用策略模式
分类 | 设计模式 |
---|---|
创建型模式 | 工厂方法模式(Factory Method Pattern) |
抽象工厂模式(Abstract Factory Pattern) | |
建造者模式(Builder Pattern) | |
原型模式(Prototype Pattern) | |
单例模式(Singleton Pattern) | |
结构型模式 | 适配器模式(Adapter Pattern) |
桥梁模式/桥接模式(Bridge Pattern) | |
组合模式(Composite Pattern) | |
装饰模式(Decorator Pattern) | |
门面模式/外观模式(Facade Pattern) | |
享元模式(Flyweight Pattern) | |
代理模式(Proxy Pattern) | |
行为模式 | 责任链模式(Chain of Responsibility Pattern) |
命令模式(Command Pattern) | |
解释器模式(Interpreter Pattern) | |
迭代器模式(Iterator Pattern) | |
中介者模式(Mediator Pattern) | |
备忘录模式(Memento Pattern) | |
观察者模式(Observer Pattern) | |
状态模式(State Pattern) | |
策略模式(Strategy Pattern) | |
模板方法模式(Template Method Pattern) | |
访问者模式(Visitor Pattern) |
创建型模式
提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性
类型说明 | 业务场景 | 实现要点 |
---|---|---|
工厂方法 | 多种类型商品不同皆苦,统一发奖服务搭建场景 | 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行 |
抽象工厂 | 替换Redis双集群升级,代理类抽象场景 | 提供⼀个创建⼀系列相关或相互依赖对象的接⼝,⽽⽆需指定它们具体的类 |
建造者 | 各项装修物料组合套餐选配场景 | 将⼀个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示 |
原型 | 上机考试多套试,每⼈题⽬和答案乱序排列场景 | ⽤原型实例指定创建对象的种类,并且通过拷⻉这些原型创建新的对象 |
单例 | 7种单例模式案例 推荐枚举单例模式 | 保证⼀个类仅有⼀个实例,并提供⼀个访问它的全局访问点 |
结构型模式
介绍如何将对象和类组装成较⼤的结构, 并同时保持结构的灵活和⾼效
类型说明 | 业务场景 | 实现要点 |
---|---|---|
适配器 | 从多个MQ消息体中,抽取指定字段值场景 | 将⼀个类的接⼝转换成客户希望的另外⼀个接⼝。适配器模式使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作 |
桥接 | 多⽀付渠道(微信、⽀付宝)与多⽀付模式(刷脸、指纹)场景 | 将抽象部分与实现部分分离,使它们都可以独⽴的变化 |
组合 | 营销差异化⼈群发券,决策树引擎搭建场景 | 将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得⽤户对单个对象和组合对象的使⽤具有⼀致性 |
装饰者 | SSO单点登录功能扩展,增加拦截⽤户访问⽅法范围场景 | 动态地给⼀个对象添加⼀些额外的职责。就增加功能来说,装饰器模式相⽐⽣成⼦类更为灵活 |
外观(门面) | 基于SpringBoot开发⻔⾯模式中间件,统⼀控制接⼝⽩名单场景 | 为⼦系统中的⼀组接⼝提供⼀个⼀致的界⾯,外观模式定义了⼀个⾼层接⼝,这个接⼝使得这⼀⼦系统更加容易使⽤ |
享元 | 基于Redis秒杀,提供活动与库存信息查询场景 | 运⽤共享技术有效地⽀持⼤量细粒度的对象 |
代理 | 模拟mybatis-spring中定义DAO接⼝,使⽤代理类⽅式操作数据库原理实现场景 | 为其他对象提供⼀种代理以控制对这个对象的访问 |
行为模式
负责对象间的高效沟通和职责委派
类型说明 | 业务场景 | 实现要点 |
---|---|---|
责任链 | 模拟618电商⼤促期间,项⽬上线流程多级负责⼈审批场景 | 避免请求发送者与接收者耦合在⼀起,让多个对象都有可能接收请求,将这些对象连接成⼀条链,并且沿着这条链传递请求,直到有对象处理它为⽌ |
命令 | 模拟⾼档餐厅⼋⼤菜系,⼩⼆点单厨师烹饪场景 | 将⼀个请求封装成⼀个对象,从⽽可以⽤不同的请求对客户进⾏参数化 |
迭代器 | 模拟公司组织架构树结构关系,深度迭代遍历⼈员信息输出场景 | 提供⼀种⽅法顺序访问⼀个聚合对象中各个元素, ⽽⼜⽆须暴露该对象的内部表示 |
中介者 | 按照Mybatis原理⼿写ORM框架,给JDBC⽅式操作数据库增加中介者场景 | ⽤⼀个中介对象来封装⼀系列的对象交互,中介者使各对象不需要显式地相互引⽤,从⽽使其耦合松散,⽽且可以独⽴地改变它们之间的交互 |
备忘录 | 模拟互联⽹系统上线过程中,配置⽂件回滚场景 | 在不破坏封装性的前提下,捕获⼀个对象的内部状态,并在该对象之外保存这个状态 |
观察者 | 模拟类似⼩客⻋指标摇号过程,监听消息通知⽤户中签场景 | 定义对象间的⼀种⼀对多的依赖关系,当⼀个对象的状态发⽣改变时,所有依赖于它的对象都得到通知并被⾃动更新 |
状态 | 模拟系统营销活动,状态流程审核发布上线场景 | 允许对象在内部状态发⽣改变时改变它的⾏为,对象看起来好像修改了它的类 |
策略 | 模拟多种营销类型优惠券,折扣⾦额计算策略场景 | 定义⼀系列的算法,把它们⼀个个封装起来,并且使它们可相互替换 |
模板方法 | 模拟爬⾍各类电商商品,⽣成营销推⼴海报场景 | 定义⼀个操作中的算法的⻣架,⽽将⼀些步骤延迟到⼦类中。模板⽅法使得⼦类可以不改变⼀个算法的结构即可᯿定义该算法的某些特定步骤 |
访问者 | 模拟家⻓与校⻓,对学⽣和⽼师的不同视⻆信息的访问场景 | 主要将数据结构与数据操作分离 |
Powered by Waline v3.1.3