# 设计模式
# 设计模式定义
设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结
# 设计模式原则
目的:减少耦合,降低复杂度,增强复用性,降低代码的开发维护扩展成本
# 单一职责原则
✖ 不符合单一职责原则
function render() {
// 1、发请求,获取数据
// 2、将数据转换为dom
// 3、dom 插入到 html
// res:[{id:1,name:'张三'}]
let html = "<ul>";
fetch("url2").then(res => {
const data = [{ id: 1, name: "张三" }, { id: 2, name: "李四" }];
data.forEach(item => {
html += `<li>${item.name}</li>`;
});
html += "</ul>";
document.getElementById("root").innerHTML = html;
});
}
render();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
✔ 符合单一职责原则
function getData() {
return fetch("url2").then(res => {
const data = [{ id: 1, name: "张三" }, { id: 2, name: "李四" }];
return data;
});
}
function createDOM(data) {
let html = "<ol>";
data.forEach(item => {
html += `<li>${item.name}</li>`;
});
html += "</ol>";
return html;
}
function renderDOM(html) {
document.getElementById("root").innerHTML = html;
}
async function init() {
// 获取数据
const data = await getData();
// 构建dom
const dom = createDOM(data);
// 渲染dom
renderDOM(dom);
}
init();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 开闭原则
对修改关闭,对拓展开放
初始需求
// 增加新的属性 school
class Student {
constructor(name, age) {
this.name = name;
this.age = age;
}
getInfo() {
console.log(this.name, this.age);
}
}
var student = new Student("张三", 22);
student.getInfo();
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
增加新需求后
✖ 不符合开闭原则
class Student {
constructor(name, age, school) {
this.name = name;
this.age = age;
this.school = school;
}
getInfo() {
console.log(this.name, this.age, this.school);
}
}
var student = new Student("张三", 22);
student.getInfo();
var student2 = new Student("李四", 25, "北京大学");
student2.getInfo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
✔ 符合开闭原则
class Student {
constructor(name, age) {
this.name = name;
this.age = age;
}
getInfo() {
console.log(this.name, this.age);
}
}
class CollageStudent extends Student {
constructor(name, age, school) {
super(name, age);
this.school = school;
}
getInfo() {
console.log(this.name, this.age, this.school);
}
}
var student = new Student("张三", 22);
student.getInfo();
var student2 = new CollageStudent("李四", 25, "北京大学");
student2.getInfo();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 里氏替换原则
任何基类可以出现的地方,子类一定可以出现
class Reactangle {
constructor(x, y) {
this.width = x;
this.height = y;
}
getArea() {
console.log("矩形的面积是:", this.width * this.height);
}
setHeight(y) {
this.height = y;
}
}
// const reactangle = new Reactangle(10, 20);
// reactangle.getArea();
// reactangle.setHeight(200)
// reactangle.getArea();
class Square extends Reactangle {
constructor(x) {
super(x, x);
}
getArea() {
console.log("矩形的面积是:", this.width ** 2);
}
}
const square = new Square(10);
square.getArea();
square.setHeight(200);
square.getArea();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 迪米特法则,又称最少知道原则
一个接口和一个方法,传入的参数越少越好
✖ 不符合迪米特法则
function getData(obj) {
return axios.get({
url: "url",
params: { obj.id }
});
}
const obj = { id: 123, name: "xxx" };
getData(obj);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
✔ 迪米特法则
function getData(id) {
return axios.get({
url: "url",
params: { id }
});
}
const obj = { id: 123, name: "xxx" };
getData(obj.id);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 接口分离原则
把大接口拆分成小接口
✖ 不符合接口分离原则
interface IAnimal {
eat: Function;
fly: Function;
run: Function;
}
class Dog implements IAnimal {
eat() {}
run() {}
// fly(){}
}
class Swallow implements IAnimal {
eat() {}
fly() {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
✔ 接口分离原则
interface IAnimal {
eat: Function;
}
interface IAnimalSky extends IAnimal {
fly: Function;
}
interface IAnimalLand extends IAnimal {
run: Function;
}
class Dog implements IAnimalLand {
eat() {}
run() {}
// fly(){}
}
class Swallow implements IAnimalSky {
eat() {}
fly() {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 依赖倒转原则
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
✖ 依赖倒转原则
// 保存朋友圈
class Web {
matchRouter() {
console.log("获取到http请求,转发到对应的service层进行处理");
// 直接依赖 service 层
new OrderService().doJob();
new Service().doJob();
}
}
class OrderService {
doJob() {
console.log("接收到web层的数据,进行数据加工,并转发到对应的db层");
// 直接依赖 db 层
new MYSQLDb().insert("data");
new MONGODb().insert("data");
new SqlServerDb().insert("data");
}
}
class ShopService {
doJob() {
console.log("接收到web层的数据,进行数据加工,并转发到对应的db层");
// 直接依赖 db 层
new MYSQLDb().insert("data");
new SqlServerDb().insert("data");
}
}
class MYSQLDb {
insert(data) {
console.log("将数据 data 存入 mysql 数据库。");
}
}
class MONGODb {
insert(data) {
console.log("将数据 data 存入 mongodb 数据库。");
}
}
class SqlServerDb {
insert(data) {
console.log("将数据 data 存入 sqlServer 数据库。");
}
}
document.getElementById("submit").addEventListener("click", () => {
// 模拟提交
new Web().matchRouter();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
✔ 依赖倒转原则
// 保存朋友圈
class Web {
constructor(service) {
this.service = service;
}
matchRouter() {
console.log("获取到http请求,转发到对应的service层进行处理");
// 直接依赖 service 层
this.service.doJob();
// 发布一个事件,在其他的地方监听这个事件
// 监听可以有很多,这就实现了一个一对多的关系
}
}
class Service {
constructor(db) {
this.db = db;
}
doJob(db) {
console.log("接收到web层的数据,进行数据加工,并转发到对应的db层");
// 直接依赖 db 层
this.db.insert("data");
}
}
class MySQLDb {
insert(data) {
console.log("将数据 data 存入 mysql 数据库。");
}
}
class MonGoDb {
insert(data) {
console.log("将数据 data 存入 mysql 数据库。");
}
}
document.getElementById("submit").addEventListener("click", () => {
// 模拟提交
const db = new MySQLDb();
const service = new Service(db);
const web = new Web(service);
// const db = new MySQLDb()
// const service = new Service(db);
// const web = new Web(service)
const db2 = new MonGoDb();
const service2 = new Service(db2);
const web2 = new Web(service2);
web.matchRouter();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
发布订阅————观察者模式
class Web {
matchRouter() {
console.log("匹配到前端路由,触发路由匹配的事件");
Observer.publish("onRouteChange");
}
}
class Service {
doJob() {
console.log("监听到路由匹配的事件,开始处理业务逻辑");
console.log("发布业务逻辑处理完成事件");
Observer.publish("onJobDone");
}
}
class Db {
selectData() {
console.log("查询数据");
}
}
var Observer = (function() {
var _message = {};
return {
subscribe(type, fn) {
if (_message[type]) {
_message[type].push(fn);
} else {
_message[type] = [fn];
}
},
publish(type, ...args) {
if (!_message[type]) {
return;
}
_message[type].forEach(item => {
item.apply(this, args);
});
},
unsubscribe(type, fn) {
// fn不传,清楚type上所有的订阅,否则只清除传递的订阅
if (!_message[type]) {
return;
}
if (fn) {
_message[type].forEach(function(item, index) {
item === fn && _message[type].splice(index, 1);
});
} else {
_message[type] = null;
}
}
};
})();
// 注册事件
Observer.subscribe("onRouteChange", new Service().doJob);
Observer.subscribe("onJobDone", new Db().selectData);
new Web().matchRouter();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 设计模式分类
# 创建型
创建型,研究高效的创建对象
- 单例模式
- 抽象工厂模式
- 建造者模式
- 工厂模式
- 原型模式
# 结构型
结构型,设计对象和结构之间的关系
- 外观模式
- 适配器模式
- 代理模式
- 装饰器模式
- 桥接模式
- 组合模式
- 享元模式
# 行为型
行为型,设计对象的行为
- 模板方法模式
- 观察者模式
- 状态模式
- 策略模式
- 职责链模式
- 命令模式
- 访问者模式
- 中介者模式
- 备忘录模式
- 迭代器模式
- 解释器模式
# 设计模式实战
- 发布订阅模式
- 单例模式
- 工厂模式
- 代理模式
- 命令模式