Decorators make it possible to annotate and modify classes and properties at design time.
装饰器可以让你在设计时对类和类的属性进行注解和修改
通俗来说,就是在不改变原有对象的基础上,通过对其进行包装扩展(添加属性或者方法)使原有对象可以满足用户更复杂的需求。就增加功能来说,装饰模式相对生成子类更为灵活。
装饰模式有不同的实现方法,
第一种,使用继承方式,构建装饰类,传入被装饰类,进行修饰;
//被装饰的类
class Component{
public operate(){
console.log("做些事...");
}
}
//装饰类
class Decorator extends Component{
private component:Component
constructor(){
super();
this.component = new Component();
}
//传入扩展功能函数
DecorOperate(method:Function){
this.operate = ()=>{
method.call(this.component);
this.component.w();
}
}
}
这种实现方式其实看起来和代理模式有些像,但代理目的是在目标对象方法基础上的增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。而装饰模式不会对目标对象的方法做操作,只做增加,做扩展。
第二种,使用注解方式,直接修改类及其成员,比如说使用装饰器,TS、ES都有。
参数:
类的构造函数作为其唯一的参数。
返回值:
返回的构造函数来替换类的声明。
function addAge(constructor: Function) {
}
@addAge
class A{
}
相当于
A = addAge(A) || A;
参数:
返回值:
用作方法的属性描述符。
如果同一个方法有多个装饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行。
// 声明装饰器修饰方法
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor)
{
...};
class A{
name: string;
constructor() {
this.name = 'xiaomuzhu'; }
@method
say(){
}
}
相当于
let descriptor = {
value: function() {
},
enumerable: false,
configurable: true,
writable: true
};
descriptor = method(A.prototype, "say", descriptor) || descriptor; Object.defineProperty(A.prototype, "say", descriptor);
同方法装饰器。
参数:
返回值:
忽略,没办法监视或修改一个属性的初始化方法,属性描述符只能用来监视类中是否声明了某个名字的属性。
// 声明装饰器修饰方法
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor)
{
...};
class A{
@method
name: string;
constructor() {
this.name = 'xiaomuzhu'; }
}
相当于
method(A.prototype, "name")
应用于类的构造函数或方法声明。
参数:
返回值:
忽略,只能用来监视一个方法的参数是否被传入。
有这么一个说法,如果超过两层继承,就要考虑代码是不是设计有问题。装饰模式就是对继承的有力补充,解决类膨胀的问题。但多层的装饰也是很复杂,不便维护的。装饰模式,优点就是扩展性十分好,对类和对象都是一种良性扩展,不需要了解其内部具体实现,只在外部进行一次封装扩展,这是对原有功能完整性的一种保护。
参考链接:TypeScript装饰器
参考书籍:《设计模式之禅》