设计模式原则
这节为设计模式的前置知识。
单一职责原则:
一个类(大到模块,小到方法)承担的职责越多,复用可能性更小
因为当一个职责变化时, 可能会影响其它功能的运作,
因此需要将这些职责进行分离,封装在不同的类中,
将不同的变化原因封装在不同的类中
单一职责原则(定义作用及经典例子详解) – mikechen的互联网架构
符合单一职责原则的设计模式:
- 工厂模式(
Factory Pattern):
将对象的创建(Factory)职责单独建立,每个工厂完成自己的工作,满足单一职责原则。
- 适配器模式(
Adapter Pattern):
将目标类和需要适配的类(Adaptee类)的适配职责分离,使用适配器来进行接口适配,从而实现单一职责。
- 装饰者模式(
Decorator Pattern):
通过将具体组件和装饰分离,每个装饰类为目标类添加特有的功能,从而实现单一职责。
- 代理模式(
Proxy Pattern):
将代理职责和实际服务分离开来, 代理添加代理方法,实际服务完成自己的方法,也实现了单一职责。
- 模板方法模式(
Template Method Pattern):
将算法框架和具体算法分离为模板方法和基本方法, 基本方法各自完成自己的任务,实现单一职责。
- 单例模式(
Singleton Pattern):
仅负责实例化和返回单例对象,而不是管理单例生命周期, 从而实现单一职责。
开闭原则(主要实现可复用性):对扩展开放,修改关闭
- 软件设计应该易于扩展,但不易于修改
- 当软件需求有变化时,我们应该扩展软件的行为,而不是去修改原来的代码
比如我们使用抽象方法,这样有利于我们添加新的实现方法。
- 策略模式(
Strategy Pattern)
定义多个具体策略类, 在运行时传入参数来判断需要哪种具体策略, 添加只用新建策略类, 符合开闭原则。
- 观察者模式(
Observer Pattern)
观察者模式可以在不修改主题对象的情况下添加新的观察者,只需要addObserver即可,符合开闭原则。
- 工厂方法模式(
Factory Method Pattern)
定义一个创建对象的接口, 工厂子类来创建类实例; 当需要新添产品时,直接新建一个具体工厂和具体产品即可, 符合开闭原则。
- 抽象工厂模式(
Abstract Factory Pattern)
提供一个创建相关对象的接口, 具体逻辑由子类实现,符合开闭原则。
- 模板方法模式(
Template Method Pattern)
定义一个操作中的算法的框架,将一些步骤延迟到子类中实现,当需要不同的实现时,新添加一个子类就行,符合开闭原则。
- 组合模式(
Composite Pattern)
将对象组合成树形结构来表示"部分-整体"的层次结构,在不改变其他对象的情况下增添新子类型,满足开闭原则。
- 装饰器模式(
Decorator Pattern)
动态地给一个对象添加一些额外的职责,在不修改对象自身情况下扩展其功能,符合开闭原则。
里氏代换原则:其实就是替换原则
所有引用基类的地方必须能透明的使用其子类的对象
意思就是父类对象一定可以指向子类对象,当我们不知道具体会创建哪种子类对象时,我们使用它的抽象类去指向即将要创建的子类对象,这样客户端使用时就不会觉得有区别。
依赖倒转原则: 高层模块不应该依赖低层模块,它们都应该依赖抽象。
高层模块不应该直接使用底层模块,而应该使用底层模块的抽象
这样高层模块和低层模块之间就不直接依赖了,而是通过中间的接口。
如果低层模块改变,只要继续实现接口,高层模块就不需要修改。
接口隔离原则:(客户端不应该依赖那些它不需要的接口)
- 接口太大,需要将它分割为一些更细小的接口
- 使用该接口的客户端仅需知道与之相关的方法即可
- 每一个接口完成自己的功能,不能有不相关的功能
比如:
interface Animal {
public void eat();
public void travel();
}
class Dog implements Animal {
public void eat() { ... }
public void travel() { ... }
}
这里 Dog 实现了 Animal 接口,但是它不需要 travel() 方法。这违背了接口隔离原则。
那应该怎么做呢?
将接口拆分为两个:
interface Pet {
public void eat();
public void sleep();
}
interface WorkAnimal {
public void travel();
}
合成复用原则(又称组合/聚合复用原则):
优先使用对象组合,而不是通过继承来达到目的。
合成复用原则就是在一个新的对象通过关联关系(聚合,组合)来使用一些已有的对象,使之成为新对象的一部分。\
尽量使用组合/聚合的方式替代继承关系
这是因为:
- 继承可能会导致类等级结构过于复杂
- 继承引入了强耦合,不利于代码扩展与维护
而使用组合/聚合:
- 创建更松耦合的关系
- 当一个类变化时,其他类不会受影响
- 避免子类数量爆炸
分析:
- 继承复用: 实现简单,运行时不能发生改变,灵活性低。
- 组合复用:耦合度低,比较灵活,但可能会导致系统中的对象过多。
迪米特法则: (又称最小知识原则): 每一个软件单位都有最小的知识原则
可能会和单一职责搞混,单一职责是让类的功能尽可能少,迪米特法则是避免超出合作者的直接职责范围
比如: 我是老板,我只用叫经理办事,而不是直接去通知员工干事。
作用是:
- 减少对象之间的间接关联和复杂交互
- 仅与直接的合作者交互,避免超出合作者的直接职责范围
- 减少耦合,提高可读性和可维护性
UML类图
大家要学习设计模式之前,必须先要看得懂类图,经常会用到,所以我给大家一个链接: