Skip to content

Commit cc19c95

Browse files
committed
✨ feat: 添加装饰者模式
1 parent b2c049f commit cc19c95

File tree

3 files changed

+270
-0
lines changed

3 files changed

+270
-0
lines changed

Decorator/Decorator-babel.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"use strict";
2+
3+
var _class;
4+
5+
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
6+
7+
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8+
9+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
10+
11+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
12+
13+
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; }
14+
15+
function decorateSword(target, key, descriptor) {
16+
// 首先获取到 init 方法
17+
var initMethod = descriptor.value; // 宝剑添加攻击力 100 点
18+
19+
var moreAtk = 100;
20+
var returnObj;
21+
22+
descriptor.value = function () {
23+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
24+
args[_key] = arguments[_key];
25+
}
26+
27+
args[0] += moreAtk;
28+
returnObj = initMethod.apply(target, args);
29+
return returnObj;
30+
};
31+
}
32+
33+
function decorateArmour(target, key, descriptor) {
34+
// 首先获取到 init 方法
35+
var initMethod = descriptor.value; // 护甲添加防御力 100 点
36+
37+
var moreDef = 100;
38+
var returnObj;
39+
40+
descriptor.value = function () {
41+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
42+
args[_key2] = arguments[_key2];
43+
}
44+
45+
args[1] += moreDef;
46+
returnObj = initMethod.apply(target, args);
47+
return returnObj;
48+
};
49+
}
50+
51+
var Warrior = (_class =
52+
/*#__PURE__*/
53+
function () {
54+
function Warrior() {
55+
var atk = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 50;
56+
var def = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 50;
57+
var hp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 100;
58+
var mp = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 100;
59+
60+
_classCallCheck(this, Warrior);
61+
62+
this.init(atk, def, hp, mp);
63+
}
64+
65+
_createClass(Warrior, [{
66+
key: "init",
67+
value: function init(atk, def, hp, mp) {
68+
this.atk = atk;
69+
this.def = def;
70+
this.hp = hp;
71+
this.mp = mp;
72+
}
73+
}, {
74+
key: "toString",
75+
value: function toString() {
76+
return "\u653B\u51FB\u529B:".concat(this.atk, ", \u9632\u5FA1\u529B: ").concat(this.def, ", \u8840\u91CF: ").concat(this.hp, ", \u6CD5\u529B\u503C: ").concat(this.mp);
77+
}
78+
}]);
79+
80+
return Warrior;
81+
}(), (_applyDecoratedDescriptor(_class.prototype, "init", [decorateSword, decorateArmour], Object.getOwnPropertyDescriptor(_class.prototype, "init"), _class.prototype)), _class);
82+
var Reaper = new Warrior();
83+
console.log("\u52C7\u8005\u72B6\u6001 => ".concat(Reaper));

Decorator/Decorator.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
function decorateSword(target, key, descriptor) {
2+
// 首先获取到 init 方法
3+
const initMethod = descriptor.value
4+
// 宝剑添加攻击力 100 点
5+
let moreAtk = 100
6+
let returnObj
7+
descriptor.value = (...args) => {
8+
args[0] += moreAtk
9+
returnObj = initMethod.apply(target, args)
10+
return returnObj
11+
}
12+
}
13+
14+
function decorateArmour(target, key, descriptor) {
15+
// 首先获取到 init 方法
16+
const initMethod = descriptor.value
17+
// 护甲添加防御力 100 点
18+
let moreDef = 100
19+
let returnObj
20+
descriptor.value = (...args) => {
21+
args[1] += moreDef
22+
returnObj = initMethod.apply(target, args)
23+
return returnObj
24+
}
25+
}
26+
27+
28+
class Warrior {
29+
constructor(atk=50, def=50, hp=100, mp=100) {
30+
this.init(atk,def,hp,mp)
31+
}
32+
@decorateSword
33+
@decorateArmour
34+
init(atk, def, hp, mp) {
35+
this.atk = atk
36+
this.def = def
37+
this.hp = hp
38+
this.mp = mp
39+
}
40+
41+
toString() {
42+
return `攻击力:${this.atk}, 防御力: ${this.def}, 血量: ${this.hp}, 法力值: ${this.mp}`
43+
}
44+
}
45+
46+
47+
const Reaper = new Warrior()
48+
49+
console.log(`勇者状态 => ${Reaper}`)

Decorator/Decorator.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# 装饰者模式
2+
3+
> 装饰者模式是在不改变对象自身的基础上,在程序运行期间给对象动态地添加方法。
4+
>
5+
> 本章节的示例需要 babel 支持修饰器模式
6+
7+
装饰者模式非常贴合 JavaScript 动态语言的特性,因为我们可以轻易的改变某个对象,但同时,因为函数是`一等公民`,所以我们会避免直接改写某个函数,来保护代码的可维护性和可扩展性。
8+
9+
其实就像我们拍照后添加的`滤镜`,不同的滤镜给照片赋予了不同的意境,这就是装饰者模式,通过滤镜装饰了照片,而并没有修改照片本身就给其添加了功能。
10+
11+
下面来举一个例子:
12+
13+
#### 初始实例
14+
15+
加入此时你是以为勇者 但勇者当前只有初始数值
16+
17+
```javascript
18+
class Warrior {
19+
constructor(atk=50, def=50, hp=100, mp=100) {
20+
this.init(atk,def,hp,mp)
21+
}
22+
23+
init(atk, def, hp, mp) {
24+
this.atk = atk
25+
this.def = def
26+
this.hp = hp
27+
this.mp = mp
28+
}
29+
30+
toString() {
31+
return `攻击力:${this.atk}, 防御力: ${this.def}, 血量: ${this.hp}, 法力值: ${this.mp}`
32+
}
33+
}
34+
35+
36+
const Reaper = new Warrior()
37+
38+
console.log(`勇者状态 => ${Reaper}`) // 勇者状态 => 攻击力:50, 防御力: 50, 血量: 100, 法力值: 100
39+
```
40+
41+
#### 装饰器的使用
42+
43+
之后我们为勇者配备一把圣剑,创建一个 `decorateSword` 方法,注意这个方法是装饰在`init` 上的
44+
45+
```javascript
46+
// 本质是使用了 Object.defineProperty 方法
47+
function decorateSword(target, key, descriptor) {
48+
// 首先获取到 init 方法
49+
const initMethod = descriptor.value
50+
// 宝剑添加攻击力 100 点
51+
let moreAtk = 100
52+
let returnObj
53+
descriptor.value = (...args) => {
54+
args[0] += moreAtk
55+
returnObj = initMethod.apply(target, args)
56+
return returnObj
57+
}
58+
}
59+
60+
61+
62+
class Warrior {
63+
constructor(atk=50, def=50, hp=100, mp=100) {
64+
this.init(atk,def,hp,mp)
65+
}
66+
@decorateSword
67+
init(atk, def, hp, mp) {
68+
this.atk = atk
69+
this.def = def
70+
this.hp = hp
71+
this.mp = mp
72+
}
73+
74+
toString() {
75+
return `攻击力:${this.atk}, 防御力: ${this.def}, 血量: ${this.hp}, 法力值: ${this.mp}`
76+
}
77+
}
78+
79+
80+
const Reaper = new Warrior()
81+
82+
console.log(`勇者状态 => ${Reaper}`) // 勇者状态 => 攻击力:150, 防御力: 50, 血量: 100, 法力值: 100
83+
```
84+
85+
#### 装饰器的叠加
86+
87+
现在,我们这位勇者的防御力还太低了,我们需要为勇者再增添一个护甲
88+
89+
```typescript
90+
91+
// 省略decorateSword
92+
93+
function decorateArmour(target, key, descriptor) {
94+
// 首先获取到 init 方法
95+
const initMethod = descriptor.value
96+
// 护甲添加防御力 100 点
97+
let moreDef = 100
98+
let returnObj
99+
descriptor.value = (...args) => {
100+
args[1] += moreDef
101+
returnObj = initMethod.apply(target, args)
102+
return returnObj
103+
}
104+
}
105+
106+
107+
class Warrior {
108+
constructor(atk=50, def=50, hp=100, mp=100) {
109+
this.init(atk,def,hp,mp)
110+
}
111+
@decorateSword
112+
@decorateArmour
113+
init(atk, def, hp, mp) {
114+
this.atk = atk
115+
this.def = def
116+
this.hp = hp
117+
this.mp = mp
118+
}
119+
120+
toString() {
121+
return `攻击力:${this.atk}, 防御力: ${this.def}, 血量: ${this.hp}, 法力值: ${this.mp}`
122+
}
123+
}
124+
125+
126+
const Reaper = new Warrior()
127+
128+
console.log(`勇者状态 => ${Reaper}`) // 勇者状态 => 攻击力:150, 防御力: 150, 血量: 100, 法力值: 100
129+
```
130+
131+
我们成功的让勇者升级了,他终于可以打败大魔王了(没准还是个史莱姆)
132+
133+
### 总结:
134+
135+
装饰者一般也用来实现 AOP (面向切面编程)利用AOP可以对业务逻辑的各个部分进行隔离,也可以隔离业务无关的功能比如日志上报、异常处理等,从而使得业务逻辑各部分之间的耦合度降低,提高业务无关的功能的复用性,也就提高了开发的效率。
136+
137+
装饰者模式与代理模式类似,但代理模式的意图是不直接访问实体,为实体提供一个替代者,实体内定义了关键功能,而代理提供或拒绝对实体的访问,或者一些其他额外的事情。而装饰者模式的作用就是为对象动态地加入行为。
138+

0 commit comments

Comments
 (0)