02-JS设计模式
码路教育 6/28/2001
# 一. 观察者设计模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="box"></div>
<script src='js/jquery-3.2.1.min.js'></script>
<script>
// 观察者设计模式 基于发布订阅
// 观察者 Foreign
// 被观察者 RMB 需要保存观察者
// 人民币类
function RMB() {
// 创建人民币输入框的dom
this.$dom = $("<div><span>人民币:</span><input type='text'/></div>");
// 追加节点
$("#box").append(this.$dom)
// 保存了观察者(订阅者)
// 在被观察者中保存了所有观察者
this.subscribes = [];
// 初始化监听
this.bindEvent();
}
RMB.prototype.subscribe = function(obj) {
this.subscribes.push(obj)
}
RMB.prototype.bindEvent = function() {
let that = this;
this.$dom.find("input").bind("input", function() {
// 通知所有的观察者重新计算
for (let i = 0; i < that.subscribes.length; i++) {
that.subscribes[i].update($(this).val());
}
})
}
var rmb = new RMB()
// 外币类
function Foreign(title, rate) {
this.title = title;
this.rate = rate;
// 外币的dom
this.$dom = $("<div><span>" + this.title +
":</span><input disabled type='text'/></div>");
$("#box").append(this.$dom);
rmb.subscribe(this)
}
Foreign.prototype.update = function(val) {
let res = val / this.rate;
this.$dom.find("input").val(res)
}
new Foreign("美元", '6.5');
new Foreign("英镑", '8.7');
new Foreign("日元", '0.063');
new Foreign("韩元", '0.0058');
</script>
</body>
</html>
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
59
60
61
62
63
64
65
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
59
60
61
62
63
64
65
# 二. 单例设计模式
<!--
JS实现单例设计模式:
一个类限制必须只能有一个实例,如果第二次创建的时候,
我们可以抛出错误或者返回第一次的实例。
-->
1
2
3
4
5
2
3
4
5
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}
let malu = new Person("码路", 17); // 码路
let manman = new Person("漫漫", 15); // 漫漫
console.log(malu);
console.log(manman);
</script>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<script>
let Person = (function() {
let instance = null;
return function(name, age) {
this.name = name;
this.age = age;
if (instance) {
return instance;
}
return instance = this;
}
})();
Person.prototype.sayHello = function() {
console.log(this.name);
}
let malu = new Person("码路", 17); // 码路
let manman = new Person("漫漫", 15); // 漫漫
console.log(malu);
console.log(manman);
console.log(malu === manman);
malu.sayHello();
manman.sayHello();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
// new Person并不是单例的
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(this.name);
}
// 创建一个代理类,实现单例设计模式
let PersonProxy = (function() {
let instance = null;
return function(name, age) {
if (instance) {
return instance;
}
return instance = new Person(name, age)
}
})()
let malu = new PersonProxy("码路", 17); // 码路
let manman = new PersonProxy("漫漫", 15); // 漫漫
console.log(malu);
console.log(manman);
console.log(malu === manman);
malu.sayHello();
manman.sayHello();
</script>
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
# 三. 组合设计模式
<script>
// 组合模式:
// 组合模式就是一组任务的顺序组合,也就是命令(任务)清单。
// 组合模式的设计哲学就是将单独的命令(任务)通过组合串联起来,形成顺序的程序列表。
// 任务清单
let coding = {
execute: function() {
console.log("coding");
}
}
let playgame = {
execute: function() {
console.log("playgame");
}
}
let eat = {
execute: function() {
console.log("eat");
}
}
let basketball = {
execute: function() {
console.log("basketball");
}
}
let meeting = {
execute: function() {
console.log("meeting");
}
};
// 工作相关的 把上面的部分任务组合成一个列表
let work = {
commands: [meeting, coding, eat],
execute() {
for (let i = 0; i < this.commands.length; i++) {
this.commands[i].execute();
}
}
}
// 娱乐相关的
let yule = {
commands: [eat, playgame, basketball],
execute() {
for (let i = 0; i < this.commands.length; i++) {
this.commands[i].execute();
}
}
}
// 把把两个组合后的任务,继续组合成一个大任务
let allDay = {
commands: [work, yule],
execute() {
for (let i = 0; i < this.commands.length; i++) {
this.commands[i].execute();
}
}
}
// work.execute();
// yule.execute();
allDay.execute();
</script>
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
59
60
61
62
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
59
60
61
62
# 四. 工厂设计模式
<script>
// 简单工厂
// 有一个工厂函数创建对象,而不是new出来的,是创建对象的方式之一
// 下面的代码就是简单的工厂的创建
// 工厂函数
function createPerson(name, age, sex) {
return {
name: name,
age: age,
sex: sex,
sayHello: function() {
console.log("你好我是" + this.name + "今年" + this.age + "岁了,我是一个" + this.sex)
}
}
};
// malu 和 manman 都是Object的实例
// 它们没有自己的对应的构造器
var malu = createPerson("码路", 12, '男生');
var manman = createPerson("漫漫", 13, "女生")
console.log(malu);
malu.sayHello();
console.log(manman);
manman.sayHello();
console.log(malu instanceof Object);
</script>
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
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
<script>
// 构造器函数
function Car(color, doors) {
this.color = color;
this.doors = doors;
}
Car.prototype.sayHello = function() {
console.log("你好,我是小汽车,我的颜色是" + this.color + "色,一共有" + this.doors + "个门");
}
// 工厂函数
function createCar(color, doors) {
return new Car(color, doors)
}
let car1 = createCar("红", 2);
let car2 = createCar("黑", 4);
console.log(car1);
console.log(car2);
console.log(car1 instanceof Car);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
// 普通工厂
// 小汽车
function Car(color, doors) {
this.color = color;
this.doors = doors;
return this
}
// 大卡车
function Trank(weight) {
this.weight = weight;
return this;
}
// 增强工厂函数
// 可以创建各种各样的对象
function createVihicle(type) {
// 根据type进行判断,到底要创建什么样的对象
if (type === "Car") {
return Car.apply(new Car(), [].slice.call(arguments, 1))
} else if (type === "Trank") {
return Trank.apply(new Trank(), [].slice.call(arguments, 1))
}
}
var xiaoqiche = new createVihicle("Car", "red", 4);
var dakache = new createVihicle("Trank", 500)
console.log(xiaoqiche)
console.log(dakache)
console.log(xiaoqiche instanceof Car)
console.log(dakache instanceof Trank);
</script>
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
<script>
// 抽象工厂就是提供一个注册方法,然后实例这个类。
// 工厂维护一个类的清单,我们用一个对象来维持当前的所有的类内容,注册的时候可以提供预审查功能。
// 比如我们要求所有的注册类都必须要有update和render方法,否则不允许注册
// 构造函数
function Duck(color, age) {
this.color = color;
this.age = age;
return this;
}
Duck.prototype.update = function() {}
Duck.prototype.render = function() {}
// 构造函数
function Chicken(color) {
this.color = color;
return this;
}
Chicken.prototype.update = function() {}
Chicken.prototype.render = function() {}
// 定义一个工厂函数
var Factory = (function() {
let types = {}; // 存储不同的构造函数,不同角色
return {
// 进行注册
// 在注册时,可以进行预审查
registFactory(type, typeFunction) {
if (!typeFunction.prototype.update || !typeFunction.prototype.render) {
throw new Error(type + "类型没有注册成功,请设置update和render方法后,再进行注册")
return
}
// 给types对象注册方法
types[type] = typeFunction
},
// 创建对象 生成对象
careateActor(type) {
return types[type].apply(new types[type](), [].slice.call(arguments, 1))
}
}
})();
// 注册
Factory.registFactory("Duck", Duck);
Factory.registFactory("Chicken", Chicken);
// 实例,必须要先注册才能进行实例
var yazi = Factory.careateActor("Duck", "黄", 1)
var xiaoji = Factory.careateActor("Chicken", "红")
console.log(yazi)
console.log(xiaoji)
</script>
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
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
# 五. 装饰者模式
<script>
// 装饰者模式
// 不改变原来的类,并且不使用继承,把一个类的进行增强
// 案例:
// 比如现在有一个学生类,他有一个方法学习,
// 学习内容是html,css,js
// 码路就是这个学生的实例
function Student() {}
Student.prototype.study = function() {
console.log("html")
console.log("css")
console.log("js")
};
// 定义一个装饰类,对Student类进行增强
function ZhuangShi(sombody) {
this.sombody = sombody
this.sombody.xixi = "xixi~"
return this.sombody;
}
var malu = new Student();
malu = new ZhuangShi(malu);
console.log(malu.xixi);
console.log(malu instanceof Student);
console.log(malu instanceof ZhuangShi);
</script>
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
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
# 六. 代理设计模式
<script>
// 代理设计模式
// 有通告需要找到明星, 先找到经纪人,不能直接和明星直接接触,经纪人进行筛选后,然后在和明星进行沟通。
// 经纪人的所作就是代理类的作用
// 案例:
// 码路同学要送花给小㺯
// 没有使用代理
function Flower(name) {
this.name = name
}
var malu = (function() {
var flower = new Flower('玫瑰花');
return {
name: '码路',
sendFlower: function(target) {
// 送的目标
target.getFlower(flower, this)
}
}
})()
var xiaomei = {
getFlower: function(flower, person) {
console.log("小美收到了" + person.name + '的' + flower.name)
}
}
malu.sendFlower(xiaomei)
</script>
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
<script>
// 突然有一天,小美和码路同学生气了,码路为了哄小红开心,想送小美礼物,
// 但是此时小美由于还在生码路的气,所以不会搭理码路。
// 此时码路想到了小美的闺蜜,让她做代理,然后把礼物送给小美的闺蜜,让闺蜜适时送给小美
function Flower(name) {
this.name = name
}
var malu = (function() {
var flower = new Flower('玫瑰花');
return {
name: '码路',
sendFlower: function(target) {
target.getFlower(flower, this)
}
}
})();
// guimi就是一个代理
var guimi = (function() {
return {
name: "闺蜜",
flower: null,
sendPeron: null,
getFlower(flower, person) {
this.flower = flower.name;
this.sendPeron = person.name;
console.log("闺蜜收到了" + person.name + "的" + flower.name);
},
getState(state) {
if (state === "心情很好" && this.flower) {
xiaomei.getFlower(this.flower, this.sendPeron);
}
}
}
})()
var xiaomei = (function() {
var state;
var timer = setInterval(function() {
if (Math.random() > 0.5) {
state = '心情很好'
} else {
state = '心情不好'
}
guimi.getState(state)
}, 1000)
// guimi.getState(state)
return {
getFlower: function(flower, person) {
// 接收自闺蜜转接的礼物
console.log("小美收到了来自闺蜜转接自" + person + "的" + flower)
}
}
})();
malu.sendFlower(guimi)
</script>
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
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0px;
padding: 0px;
}
body {
background-color: skyblue;
}
img {
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<script>
// 代理类实现图片loading
function MyImage(src) {
// 创建节点
this.oImg = document.createElement("img");
// 节点上树
document.body.appendChild(this.oImg);
}
MyImage.prototype.setSrc = function(src) {
this.oImg.src = src;
};
// 代理类
function MyImageProxy(src) {
this.myImage = new MyImage();
this.myImage.setSrc("./images/loading.gif");
// image相当于一个钩子
var image = new Image();
image.src = src;
var that = this;
image.onload = function() {
that.myImage.setSrc(src)
}
}
new MyImageProxy("./images/0.jpg")
new MyImageProxy("./images/1.jpg")
new MyImageProxy("./images/2.jpg");
</script>
</body>
</html>
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
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
# 七. 装饰者模式
1
# 六. 装饰者模式
1
# 六. 装饰者模式
1