# 设计模式-结构型模式
# 装饰器模式
使用装饰器可以装饰一个类或类中的属性
在不修改装饰对象上的代码情况下改变目标对象的行为
下面的实践均采用ts编写,使用ts-node直接运行,需在全局安装typescipt与ts-node
全局安装依赖
npm i typescript ts-node -g
 1
运行ts文件
ts-node xx.ts
 1
# 类装饰器
装饰器对象是一个类
function classDecorator(target){
    return target
}
@classDecorator
class C{
    hello(){
        console.log('hello world')
    }
}
 1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- target表示装饰的目标类
 
示例:在目标类上拓展 sayHello 方法
function helloWorld(target){
    // target === 目标类
    target.prototype.sayHello = function(){
        console.log('hello world');
    }
    return target
}
@helloWorld
class Router {
    sayHello() {
        throw new Error("Method not implemented.");
    }
}
const r = new Router()
r.sayHello() // hello world
 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
# 函数装饰器
装饰对象的值是一个函数
function funDecorator(target, name, descriptor){
    return descriptor.value
}
class C{
    @funDecorator
    hello(){
        console.log('hello world')
    }
}
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- target: 目标类的原型
 - name: 属性名
 - descriptor:属性描述符号
- value:属性值
 - writable:是否可以被重写
 - enumerable:是否可枚举
 - configurable:是否可配置
 
 
示例:提示某个方法已经失效
function expired(target, name, descriptor): any {
    console.log('fun:',name, 'is expired');
    return descriptor.value
}
@helloWorld
class Router {
    @expired
    hello() {
        // ...code
    }
    @expired
    hello2(){
        // ...code
    }
}
// fun: hello is expired
// fun: hello2 is expired
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# get/set装饰器
装饰存/取器的装饰器
- target: 静态方法指向类的构造函数,实例方法指向类的原型
 - name: 属性名
 - descriptor:属性描述符号
- value:属性值
 - writable:是否可以被重写
 - enumerable:是否可枚举
 - configurable:是否可配置
 
 
function getDecorator(target,name,descriptor){
}
function getDecorator(target,name,descriptor){
    
}
class C{
    private _x: number
    private _y: number
    constructor(x, y) {
        this._x = x
        this._y = y
    }
    @getDecorator
    get x() {
        return this._x
    }
    @getDecorator
    get y() {
        return this._y
    }
        
    @setDecorator
    set x(v) {
        this._x = v
    }
    @getDecorator
    set y(v) {
        this._y = v
    }
}
 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
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
emmmm,暂没想到用武之地
# 属性装饰器
简而言之就是装饰对象是一个普通的属性,参数和上述函数装饰器一致
函数也可以看做是类的一个属性,只不过其属性值是function
function propertyDecorator(target,name){
}
class C{
    @propertyDecorator
    private property:string|undefined
}
 1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
示例:设置默认值
function defaultValue(v: any) {
    return function (target, name) {
        target[name] = v
    }
}
class Router {
    @defaultValue('666')
    public name: string | undefined
}
const r = new Router()
console.log(r.name);
 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
其中装饰器传参实现,可以看做是一个闭包调用
在设置装饰器的时候传递参数,然后返回一个函数去真正装饰目标对象
这个被装饰的对象可以使用传递的参数
# 函数参数装饰器
顾名思义,装饰对象是函数中的一个参数
function paramDecorator(target,name,idx){
}
class C{
    fun1(@paramDecorator a){
    }
    static func2(@paramDecorator a){
    }
}
 1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- target: 静态方法指向类的构造函数,实例方法指向类的原型
 - name:属性名
 - idx:参数在函数中所处位置
 
示例:获取参数在函数中的相对位置
function printParamPos(target, name, idx) {
    console.log('paramCount:', target[name].length, 'paramPos:', idx);
}
class Router {
    hello3(@printParamPos name: string) {
        console.log('hello3', name);
    }
    static hello4(@printParamPos name: string) {
        console.log('hello4', name);
    }
}
const r = new Router()
Router.hello4('123')
r.hello3('456')
// paramCount: 1 paramPos: 0
// paramCount: 1 paramPos: 0
// hello4 123
// hello3 456
 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