设计模式--Note--大纲
Author:wangml
Date:20210904
在面对重复出现的问题,使用一套可复用的解决方案,避免重复劳动。
目标
- 理解松耦合设计思想
- 掌握面向对象设计原则
- 掌握重构技法改善设计
- 掌握GOF核心设计模式
分解与抽象
以实现一个画图窗口为例
// 分解 分而治之的思想
class Window {
public:
void drawWindow() {
...
for (auto line : lines) {
line.drawLine();
}
for (auto circle : circles) {
circle.drawCircle();
}
// 增加
...
}
private:
vector<Line> lines;
vector<Circle> circles;
// 增加
};
class Line {
public:
Line();
void drawLine();
private:
Point a;
Point b;
};
class Circle {
public:
Circle();
void drawCircle();
private:
Point o;
double len;
};
...
// 抽象
class Window {
public:
void drawWindow() {
...
for (auto shape : shapes) {
shape->draw();
}
...
}
private:
vector<Shape*> shapes;// 析构时 注意销毁
};
class Shape {
public:
Shape();
virtual void draw() {}
}
class Line : public Shape {
public:
Line();
virtual ~Line();// 使得通过Shape指针可以调用正确的析构函数
void draw();
private:
Point a;
Point b;
};
class Circle : public Shape {
public:
Circle();
virtual ~Circle();
void draw();
private:
Point o;
double len;
};
考虑,当系统需要增加一个三角形的类
此时除了实现一个新的类之外,抽象相对于分解的方法,对原代码的的改动要少得多
// 分解
class Triangle {
public:
...
void drawTriangle();
};
// 抽象
class Triangle : public Shape {
public:
void draw();
...
};
面向对象的设计
变化是复用的天敌
面向对象与软件设计
-
隔离变化:将变化带来的影响降为最小
-
微观层面:各司其职,新产生的类不影响已存在的类
类的责任
对象
- 语言层面:封装了数据和代码
- 规格层面:一系列可被使用的公共接口
- 概念层面:拥有某种责任的抽象
面向对象设计原则
依赖倒置原则DIP
-
高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
-
抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。
这两换句话在上述Window的例子中的体现:
- Window不应该因为各个形状(Line等)的变化,而需要调整自身,Window和Line等都转而依赖于抽象的Shape
- 在Shape中不应该使用具体的(Line等)的操作,而是让Line等自己负责自身的实现细节(draw)
开放封闭原则OCP
-
对扩展开放,对更改封闭
-
类模块应该是可扩展的,但不可修改
在Window中,可以扩展更多的形状(Triangle),而不比对Window做出更改
单一职责原则SRP
- 一个类应该仅有一个引起它变化的原因
- 变化的方向隐含着类的责任
Liskov替换原则LSP
- 子类必须能够替换他们的基类(IS-A)
- 继承表达类型抽象
接口隔离原则ISP
-
不应该强迫客户程序依赖它们不用的方法
-
接口应该小而完备
只public必要的,仅子类用的就protected,仅自身使用就private
优先使用对象组合而不是类继承
-
类继承通常为白箱复用,对象组合通常为黑箱复用
-
继承在某种程度上破坏了封装性,子类父类耦合度高
继承有时候导致父类对子类暴露的东西过多
-
而对象组合只要求被组合的对象具有良好的接口,耦合程度低
封装变化点
- 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良影响,从而实现层次之间的松耦合
针对接口编程而不是针对实现编程
-
不将变量类声明为某个特定的具体类,而是声明为某个接口
-
客户程序无需获知对象的具体类型,只需知道对象所具有的接口
-
减少系统中各部分的依赖关系,从而实现 高内聚,松耦合 的类型设计方案
Window的实现中,分解的实现包含了具体类的vector
,而抽象实现使用Shape*
GOF-23
模式分类
- 从目的来看
- 创建型模式
- i结构型模式
- 行为型模式
- 从范围看
- 类模式处理类与子类的静态关系
- 对象模式处理对象间的动态关系
从封装变化角度对模式分类
-
组件协作
框架与应用软件之间的划分
组件协作模式通过晚期绑定来实现框架和应用程序之间的松耦合
- Template Method
- Strategy
- Observer / Event
-
单一职责
- Decorator
- Bridge
-
对象创建
通过”对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。
它是接口抽象之后的第一步工作。
- Factory Method
- Abstract Factory
- Prototype
- Builder
-
对象性能
- Singleton
- Flyweight
-
接口隔离
- Facade
- Proxy
- Mediator
- Adapter
-
状态变化
- Memento
- State
-
数据结构
- Composite
- Iterator
- Chain of Resposibility
-
行为变化
- Command
- Visitor
-
领域问题
- Interpreter
重构关键技法
-
静态到动态
-
早绑定到晚绑定
-
继承到组合
-
编译时依赖到运行时依赖
-
紧耦合到松耦合
从不同角度阐述同一个问题?