type
status
date
slug
summary
tags
category
icon
password
notion image

1、设计原则

1.1 面向对象设计的经典原则

软件设计原则是指导开发者编写高质量、可维护、可扩展代码的基本准则。以下是软件设计中常用的软件设计原则,包括最经典的面向对象编程的 SOLID 原则
  • SOLID 原则:
    • 单一职责原则(Single Responsibility Principle)一个类的职责应该单一,不要承担过多的职责。单一职责适用于接口、类和方法。
    • 开闭原则(Open/Closed Principle):“开”指的是对扩展开放,而“闭”则指的是对修改关闭。简单来讲就是不要修改已有的代码,而要去编写新的代码。开闭原则的核心是通过高层抽象的泛化来保证底层实现的多态化扩展,这样就不需要对现有的系统进行反复修改。
    • 里氏替换原则(Liskov Substitution Principle)所有父类能出现的地方,子类就可以出现,并且替换了也不会出现任何错误。这就要求子类的所有相同方法,都必须遵循父类的约定,否则当父类替换为子类时就会出错。面向对象设计语言的特性“继承与多态”正是为此而生。
    • 接口隔离原则(Interface Segregation Principle)接口的内容一定要尽可能地小,能有多小就多小。所以切勿将接口定义成全能型的,否则实现类就必须神通广大,这样便丧失了子类实现的灵活性。
    • 依赖倒置原则(Dependency Inversion Principle):指高层模块不依赖底层模块,也就是说高层模块只依赖上层抽象,而不直接依赖具体的底层实现,从而达到降低耦合的目的。例如面向接口编程。通过抽象成接口,使各个类的实现彼此独立,实现类之间的松耦合。
  • 迪米特法则(law of Demeter):又叫作最少知识原则(The Least Knowledge Principle),通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的 public 方法,不对外泄漏任何信息。设计模式中的门面模式(Facade)和中介模式(Mediator)都是迪米特法则的应用的例子。
  • 合成复用原则(Composition Over Inheritance):合成复用原则是指尽量使用组合/聚合,而不是使用继承。只有当以下的条件全部被满足时,才应当使用继承关系:
    • 子类是超类的一个特殊种类,而不是超类的一个角色,也就是区分“Has-A”和“Is-A”.只有“Is-A”关系才符合继承关系,“Has-A”关系应当使用聚合来描述。
    • 永远不会出现需要将子类换成另外一个类的子类的情况。如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。
    • 子类具有扩展超类的责任,而不是具有置换掉或注销掉超类的责任。如果一个子类需要大量的置换掉超类的行为,那么这个类就不应该是这个超类的子类。

1.2 一句话归纳七大设计原则

设计原则
一句话归纳
目的
适用场景
单一职责原则(SRP)(Simple Responsibility)
一个类只干一件事
便于理解,提高代码可读性
类设计
开闭原则(OCP)(Open-Close)
对扩展开放,对修改关闭
减少维护带来新的风险
系统扩展
里氏替换原则(LSP) (Liskov Substitution)
子类可替换父类(继承与多态)
防止继承泛滥
继承设计
接口隔离原则(ISP)(Interface Segregation)
接口尽可能小而专
功能解耦,高聚合、低耦合
接口设计
依赖倒置原则(DIP)(Dependence Inversion)
依赖抽象而非实现(面向接口编程)
更利于代码结构的升级扩展
依赖管理
迪米特法则(LoD)(Law of Demeter)
对其他模块知道的越少越好
只和朋友交流,不和陌生人说话,减少代码臃肿
方法设计
合成复用原则(CARP)(Composite/Aggregate Reuse)
尽量使用组合实现代码复用,而不使用继承
降低代码耦合
依赖管理
SOLID 设计原则之间的关系:
  • 开闭原则是设计的终极目标,满足该原则可以达到最大限度的复用性和可维护性。当你的代码满足其他原则时,那么基本上就是满足开闭原则的。
  • 单一职责是所有设计原则的基础。
  • 里氏替换原则强调的是子类替换父类后程序运行时的正确性,它用来帮助实现开闭原则。
  • 而接口隔离原则用来帮助实现里氏替换原则,同时它也体现了单一职责。
  • 依赖倒置原则是过程式编程与面向对象编程的分水岭,同时它也被用来指导接口隔离原则。
notion image
简单地说:
  • 依赖倒置原则告诉我们要面向接口编程。
  • 当我们面向接口编程之后,接口隔离原则和单一职责原则又告诉我们要注意职责的划分,不要什么东西都塞在一起。
  • 当我们职责捋得差不多的时候,里氏替换原则告诉我们在使用继承的时候,要注意遵守父类的约定。
  • 上面说的这四个原则,它们的最终目标都是为了实现开闭原则。

2、设计模式

设计原则(如 SOLID)是指导思想,而设计模式基于设计原则实现的具体解决方案。设计模式是软件设计中常见问题的可重用解决方案,它们代表了最佳实践,是开发者长期经验的总结。但是在使用的过程中千万不要死记硬背,生搬硬套

2.1 GoF 23种设计模式

设计模式分为三大分类
  1. 创建型模式(Creational Patterns):关注对象的创建机制,提供灵活的对象创建方式,降低系统耦合度。有 5 种设计模式:
      • 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
      • 工厂方法(Factory Method):定义创建对象的接口,但由子类决定实例化的类。
      • 抽象工厂(Abstract Factory):创建相关或依赖对象的家族,而不指定具体类。
      • 建造者模式(Builder):分步骤构建复杂对象,分离构造与表示。
      • 原型模式(Prototype):通过复制现有对象来创建新对象。
  1. 结构型模式(Structural Patterns):处理类或对象的组合,形成更大的结构。有 7 种设计模式:
      • 适配器模式(Adapter):转换接口使得不兼容的类可以合作。
      • 装饰器模式(Decorator):动态地为对象添加职责。
      • 代理模式(Proxy):为其他对象提供一种代理以控制访问。
      • 组合模式(Composite):将对象组合成树形结构以表示“部分-整体”层次。
      • 桥接模式(Bridge):分离抽象与实现,使它们可以独立变化。
      • 外观模式(Facade):为子系统提供统一的简化接口。
      • 享元模式(Flyweight):共享细粒度对象以减少内存占用。
  1. 行为型模式(Behavioral Patterns):关注对象间的通信和职责分配。有 11 种设计模式:
      • 策略模式(Strategy):定义算法族,使其可互换。
      • 观察者模式(Observer):定义对象间的一对多依赖,当一个对象状态改变时,所有依赖者自动更新。
      • 命令模式(Command):将请求封装为对象,支持请求的排队、日志或撤销。
      • 责任链模式(Chain of Responsibility):将请求的发送者和接收者解耦,使多个对象都有机会处理请求。
      • 状态模式(State):允许对象在内部状态改变时改变行为。
      • 模板方法(Template Method):定义算法的骨架,将某些步骤延迟到子类。
      • 迭代器模式(Iterator):提供一种方法顺序访问聚合对象的元素。
      • 中介者模式(Mediator):集中管理对象间的交互,降低耦合。
      • 备忘录模式(Memento):捕获并外部化对象的内部状态以便恢复。
      • 访问者模式(Visitor):将算法与对象结构分离,便于新增操作。
      • 解释器模式(Interpreter):定义语言的文法,并解释执行。

2.2 一句话归纳23种设计模式

设计模式
一句话归纳
目的
生活案例
框架源码举例
原型模式(Prototype )
拔一根猴毛,吹出干万个
高效创建对象
克隆
ArrayList、PrototypeBean
建造者模式(Builder)
高配中配与低配,想选哪配就哪配
开放个性配置步骤
选配
StringBuilder、BeanDefinitionBuilder
代理模式(Proxy)
没有资源没时间, 得找媒婆来帮忙
增强职责
媒婆
ProxyFactoryBean、JdkDynamicAopProxy、CglibAopProxy
门面模式(Facade)
打开一扇门,走向全世界
统一访问入口
前台
JdbcUtils、RequestFacade
装饰器模式(Decorator)
他大舅他二舅,都是他舅
灵活扩展、同宗同源
煎饼
BufferedReader、Inputstream
适配器模式(Adapter)
适合自己的,才是最好的
兼容转换
电源造配
AdvisorAdapten、HandlerAdapter
桥接模式(Bridge)
约定优于配置
不允许用继承
DriverManager
委派模式(Delegate)
这个需求很简单,怎么实现我不管
只对结果负责
授权委托书
ClassLoader、 BeanDefinitionParserDelegate
模板模式(Template)
流程全部标准化,需要微调请覆盖
逻辑复用
把大象装进冰箱
JdbcTemplate、HttpServlet
策略模式(Strategy)
条条大道通北京,具体哪条你来定
把选择权交给用户
选择支付方式
Comparator、 Instantiationstrategy
责任链模式(Chain of Responsibility)
各人自扫门前雪,莫管他人瓦上霜
解耦处理逻辑
踢皮球
FilterChain、Pipeline
迭代器模式(Iterator)
流水线上坐一天,每个包裹扫
统一对集合的访问
逐个检票进站
Iterator
命令模式(Command)
运筹帷幄之中,决胜干里之外
解耦请求和处理
遥控器
Runnable、TestCase
状态模式(State)
状态驱动行为,行为决定状态
绑定状态和行为
订单状态跟踪
Lifecycle
备忘录(Memento)
给我一剂"后悔药“
备份
草槁箱
StateManageableMessageContext
中介者(Mediator)
联系方式我给你,怎么搞定我不管
统一管理网状资源
朋友圈
Timer
解释器模式(Interpreter)
我想说"方言",一切解释权归我所有
实现特定语法解析
摩斯密码
Pattern、ExpressionParser
观察者模式(Observer)
到点就通知我
解耦观察者与被观察者
闹钟
ContextLoaderListener
访问者模式(Visitor)
横看成岭侧成峰,远近高低各不同
解耦数据结构和数据操作
KPI考核
FileVisitor、BeanDefinitionVisitor

2.4 设计模式之间的关联和对比

单例模式和工厂模式
实际业务代码中,通常会把工厂类设计为单例。
策略模式和工厂模式
  • 工厂模式包含工厂方法模式和抽象工厂模式是创建型模式,策略模式属于行为型模式。
  • 工厂模式主要目的是封装好创建逻辑,策略模式接收工厂创建好的对象,从而实现不同的行为。
策略模式和委派模式
  • 策略模式更关注算法的可替换性
  • 委派模式更关注分发和调度的过程
代理模式与委派模式
  • 代理模式强调访问控制,代理对客户端隐藏目标对象的细节。
  • 委派模式强调职责转移,委派者将任务交给更专业的类处理。
门面模式和委派模式
  • 门面模式强调简化入口,门面是子系统的统一入口,封装实现的复杂性。
  • 委派模式强调任务分配,将具体任务分配给特定实现类。
模板方法模式和工厂方法模式
工厂方法是模板方法的一种特殊实现。
notion image
  • 对于工厂方法模式的 create() 方法而言,相当于只有一个步骤的模板方法模式。这一个步骤交给子类去实现。
  • 模板方法则将 needHomework() 方法和 checkHomework() 方法交给子类实现, needHomework() 方法和 checkHomework() 方法又属于父类的某一个步骤且不可变更。
模板方法模式和策略模式
1、 模板方法和策略模式都有封装算法。
2、 策略模式是使不同算法可以相互替换,且不影响客户端应用层的使用。
3、 模板方法是针对定义一个算法的流程,将一些有细微差异的部分交给子类实现。
4、模板方法模式不能改变算法流程,策略模式可以改变算法流程且可替换。策略模式通常用来代替 if…else…等条件分支语句。
notion image
1、WechatPay、JDPay、AliPay是交给用户选择且相互替代解决方案。而 JdbcTemplate下面的子类是不能相互代替的。
2、策略模式中的queryBalanceOTJ法虽然在pay。方法中也有调用,但是这个逻辑只是出于程序健壮 性考虑。用户完全可以自主调用que「yBalance()方法。而模板方法模式中的mapRow()方法一定要在 获 得 ResultSet之后方可调用,否则没有意义。
装饰者模式和静态代理模式
1、 装饰者模式关注点在于给对象动态添加方法,而代理更加注重控制对对象的访问。
2、 代理模式通常会在代理类中创建被代理对象的实例,而装饰者模式通常把被装饰者作为构造参数。
notion image
装饰者和代理者虽然都持有对方引用,但逻辑处理重心是不一样的。
装饰者模式和适配器模式
1、 装饰者模式和适配器模式都是属于包装器模式(Wrapper Pattern) 的实现形式。
2、 装饰者模式可以实现被装饰者与相同的接口或者继承被装饰者作为它的子类,而适配器和被适配者可以实现不同的接口。
notion image
  • 装饰者需要满足 OOP 的 is-a 关系,不管如何包装都有共同的父类。
  • 适配器主要解决兼容问题,不一定要统一父类。上图中 LoginAdapterRegistAdapter 就是兼容不同功能的两个类,但 RegistForQQAdapter需要注册后自动登录,因此既继承了 RegistAdpter 又继承了 LoginAdapter
适配器模式和静态代理模式
适配器可以结合静态代理来实现,保存被适配对象的引用,但不是唯一的实现方式。
适配器模式和策略模式
在适配业务复杂的情况下,利用策略模式优化动态适配逻辑。

2.5 设计模式使用频次总结

  • 创建型模式:
    • 高频: 工厂方法模式、抽象工厂模式、单例模式、建造者模式
    • 低频 : 原型模式
  • 结构型模式:
    • 高频: 代理模式、门面模式、装饰器模式、、适配器模式、组合模式
    • 低频 : 桥接模式、享元模式
  • 行为型模式(Behavioral)
    • 高频: 模板方法模式、策略模式、责任链模式、观察者模式
    • 低频: 备忘录模式、 迭代器模式、中介者模式、命令模式、解释器模式、访问者模式、状态模式
Spring 中的设计模式总结:Spring 就是一个把设计模式用得淋漓尽致的经典框架,其实从类的命名就能看出来:
设计模式名称
举例
工厂模式
BeanFactory
装饰器模式
BeanWrapper
代理模式
AopProxy
委派模式
DispatcherServlet
策略模式
HandlerMapping
适配器模式
HandlerAdapter
模板模式
JdbcTemplate
观察者模式
ContextLoaderListener
雪花算法介绍和实现领域驱动设计在互联网业务开发中的实践
Loading...