设计模式(11)[JS版]-JavaScript中的注解之装饰器模式

网友投稿 785 2022-05-30

目录

1 什么是装饰器模式?

2 装饰器模式的主要参与者有哪些

3 代码实现

4 实例应用

5 ES7 中的 decorator

6 总结

1 什么是装饰器模式?

装饰器模式模式动态地扩展了(装饰)一个对象的行为,同时又不改变其结构。在运行时添加新的行为的能力是由一个装饰器对象来完成的,它 "包裹 "了原始对象,用来提供额外的功能。多个装饰器可以添加或覆盖原始对象的功能。装饰器模式属于结构型模式。和适配器模式不同的是,适配器模式是原有的对象不能用了,而装饰器模式是原来的对象还能用,在不改变原有对象结构和功能的前提下,为对象添加新功能。

装饰器的一个例子是安全管理,其中业务对象被赋予了额外的访问权限,这取决于经过认证的用户的权限。例如,人力资源经理得到一个雇员对象,该对象已经附加(即装饰了)查看雇员的工资记录权限,这样该员工就可以查看工资信息了。装饰器通过允许运行时更改,为静态类型的语言提供灵活性。但是,JavaScript是一种动态语言,并且在运行时扩展对象的能力已融入该语言本身。

2 装饰器模式的主要参与者有哪些

参与该模式的对象有:

客户端(Client) :维护一个对被装饰的组件的引用。

组件(Component) :添加了附加功能的对象。

装饰器(Decorator) :

1.通过保持对Component的引用来 "包装 "它。

2. 定义了一个符合Component接口的接口。

3.实现附加功能(图中addedMembers)。

3 代码实现

在下面的代码中,一个User对象被一个DecoratedUser对象装饰(增强),它扩展了User的地址属性。因为原始接口必须保持不变,所以user.name会被分配给this.name。另外,DecoratedUser的say方法隐藏了User的say方法。

这是装饰器模式的经典实现,但是JavaScript本身的一些语法,就可以更有效的在运行时扩展对象,所以在实际开发中我们一般不会用到这种方法。日志函数用来记录和显示结果。

装饰器模式:公众号AlbertYang

4 实例应用

装饰器模式:公众号AlbertYang

5 ES7 中的 decorator

在ES7中提供了一种类似于java注解的语法糖来实现装饰器模式。decorator的实现依赖于ES5的Object.defineProperty方法来进行扩展和封装的。装饰器是一种函数,写法是 @+函数名。在使用它之前需要引入babel模块 transform-decorators-legacy 编译成 ES5 或 ES6。

@testable

class MyTestableClass {

// ...

}

function testable(target) {

target.isTestable = true;

}

MyTestableClass.isTestable // true

@decorator

class A {}

// 等同于

class A {}

A = decorator(A) || A;

上面代码中,@testable就是一个装饰器。它修改了MyTestableClass这个类的属性,为它加上了静态属性isTestable。testable函数的参数target是MyTestableClass类本身。装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。

我们来做一个常用的mixins混合装饰器,来把一个类里面属性和方法全部添加到另一个类上

function mixins(...list) {

return function (target) {

Object.assign(target.prototype, ...list)

}

}

const Foo = {

foo() { alert('foo') }

}

@mixins(Foo)

设计模式(11)[JS版]-JavaScript中的注解之装饰器模式

class MyClass {}

let obj = new MyClass();

obj.foo() // 'foo'

装饰方法,让某个方法只读,不能修改

function readonly(target, name, descriptor){

// descriptor属性描述对象 (Object.defineProperty 会用到)

// descriptor对象原来的值如下

// {

// value: specifiedFunction,

// enumerable: false,

// configurable: true,

// writable: true

// };

descriptor.writable = false;

return descriptor;

}

class Person {

constructor() {

this.first = 'A'

this.last = 'B'

}

@readonly

testname() { return `${this.first} ${this.last}` }

}

var p = new Person()

console.log(p.testname())

p.testname = function () {} // 这里会报错,因为 name 是只读属性

实现一个日志打印装饰器

function log(target, name, descriptor) {

var oldValue = descriptor.value;

// name 是修饰的方法名字

descriptor.value = function() {

console.log(`Calling ${name} with`, arguments);

return oldValue.apply(this, arguments);

};

return descriptor;

}

class Math {

@log

add(a, b) {

return a + b;

}

}

const math = new Math();

const result = math.add(2, 4);

console.log('result', result);

在装饰类的时候,一般主要看装饰函数的target(装饰对象)即第一个参数,装饰方法的时候,一般主要看装饰函数的descriptor(描述)即第三个参数。

ES7 中的 decorator还有很多其他的用法,由于时间有限,在这里就不展开讲了,如果想要了解更多ES7 中的 decorator,可以去系统学习一下,它的实现原理和用法。

core-decorators.js是一个第三方模块,提供了几个常见的装饰器,通过它可以更好地理解装饰器。

官网文档:https://github.com/jayphelps/core-decorators.js

6 总结

装饰器模式是一种常见的结构型模式,在不改变类或对象本身结构的情况下,在程序的运行期间动态的为类或对象添加功能。与继承相比,装饰者模式是一种更轻便灵活的做法。Decorator 虽然原理非常简单,却可以实现很多实用又方便的功能,现在前端领域很多框架和库都在使用这个特性,像 mobx中@observable、Angular中的大量应用等都证明了其易用性。个人觉得在开发一些框架的时候,尝试加入装饰器可以使代码更简洁和高效,提高代码质量。

今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎,评论,转发!!!

Elasticsearch JavaScript

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Git之深入解析Rerere重用记录的解决方案
下一篇:【乘风破浪的开发者】华为云云享专家朱广建:身处最好的时代,与开发者共建万物互联的新世界
相关文章