前言
本文并非各种设计模式的具体实现,而是借由各种设计模式与实际结合,谈谈自己对其的理解。
每种设计模式的实现可看=>代码
类的三大特性
- 封装:将属性私有化(private),提供公共方法(public)进行访问修改
- 继承:为了继承属性,复用功能
- 多态:一个类有多种表现形态,继承是多态的一种形式,实现接口也是多态的一种实现方法
一、UML类关系图解读
关系 | 代码体现 | 描述 | 图示 |
---|---|---|---|
泛化 Generalization | 具体类 继承 具体类 | ![]() | |
实现 Realization | 实现接口 或 继承抽象类 | ![]() | |
组合 Composition | 内部类 是 外部类的组合/成员变量持有引用,由内部方法创建对象 | 整体与部分关系,部分与整体生命周期一致。强聚合 | ![]() |
聚合 Aggregation | 成员变量类型是外部类/成员变量持有引用,对象由外部传入 | 整体与部分关系,部分可以脱离整体存在 | ![]() |
关联 Association | 成员变量类型是外部类 | 平级关系,强依赖,类本身直接关联其他类 | ![]() |
依赖 Dependency | 方法参数或返回类型是外部类 | 平级关系,一个类需要另一个类协助 调用方法时才会产生联系 | ![]() |
耦合程度由高到低: 泛化=实现>组合>聚合>关联>依赖
某种程度上,上层关系包含下层关系。依赖关系可以用关联关系形容,但是关联关系不能用依赖关系形容。
参考:
二、7个设计原则
原则 | 概括 | 举例 | 优点 | 缺点 |
---|---|---|---|---|
1. 单一职责 | 一个类只负责一个功能。 职责过多,引起变化的原因就会越多 | 实现具体逻辑的类的职责应该是单一的。查询接口调用后,会返回查询结果并留下查询记录。查询逻辑和记录逻辑写到一个类里是违反原则的。 | 降低耦合、降低逻辑复杂度 | 拆的太细上层使用时可能有重复代码 |
2. 接口隔离 | **类与类的依赖建立在最小接口上。 **实现一个接口的时候,希望接口里的方法没有用不到的。 | 一个接口里有两个方法:查询和记录方法。两者关联不大,应该拆成两个接口 | 减少实现不必要方法造成的代码冗余 | 定义接口太细会使设计复杂 |
3. 依赖倒转 | 面向接口编程 | 重点在代码高低层逻辑架构。高层不应该依赖底层。应该让多种查询操作实现同一个接口,记录方法的入参类型应该是查询操作的接口 | 降低类之间的耦合性 | |
4. 里式代换 | 目的是将父类对象替换成子类对象后程序正常运行。实际上的要求是子类可以扩展父类功能,但是不能重写父类代码。 | 重点在继承时子类的处理。 | ||
5. 开闭原则 | 对扩展开放,对修改关闭 | 新增功能时不要修改原有代码。重点是使用抽象与继承,达到扩展开放修改关闭的目的。 | ||
6. 迪米特法则 | 也称最少知道原则。有两点体现:只和直接朋友交流、减少对朋友的了解 | 1. 不要在方法内new对象,尽量使用成员变量或者方法参数 2. 减少对外暴露的方法数量,合并逻辑 | 降低耦合度 | 不是朋友的类想建立联系可能需要中介类转达,增加系统复杂度 |
7. 合成复用原则 | 尽量使用对象组合/聚合,而不是继承 | 继承叫作白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合称为黑箱复用,我们是无法获取到类以外的对象的实现细节的 | 系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少 | 类的实现细节被隐藏 |
总结下各个原则之间的关联关系:
- 单一职责的重点在类的职责,要求一个类只负责一个功能
- 接口隔离原则重点在接口里方法是不是最精简的
- 依赖倒转原则的核心是面向接口编程,重点在代码框架的设计,抽象不应该依赖细节,细节应该依赖抽象。
- 开闭原则要求使用抽象,从而能够对新增类、方法开放,对修改关闭。
- 里式替换原则要求在继承时,子类不要重写父类的方法,达到父类对象替换成子类对象后程序正常运行的目的。
- 合成复用原则要求避免继承而使用组合/聚合,降低类之间的耦合。看似和前面矛盾其实不然,合成复用常发生在关系耦合度不高的类之间,例如如人和衣服,应该人持有衣服属性,而不是人继承衣服来获取衣服的属性。
- 迪米特法则算比较复杂的法则,最少知道法则,只和直接朋友交流、减少对朋友的了解。
三、23种设计模式
创建型模式(5个)
结构型模式(7个)
行为模式(11个)
设计模式 | 概念 | 理解 |
---|---|---|
责任链 | 将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。 | if else的代替者 |
策略 | 定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。 | if if 的代替者 |
模板 | 在抽象父类中定义一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 | 抽象父类定义好流程,子类对特定步骤重写 |
命令 | 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。 | |
迭代器 | 在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。 | |
中介者 | 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 | |
备忘录 | 在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 | |
状态 | 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 | |
访问者 | 将算法与其所作用的对象隔离开来。 | |
观察者 | 定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。 |
23种设计模式类图