Do more 做的更多,比你上级给你安排的任务!
前言
在《不止代码》中提到了几个程序员典型的思维误区:
「 拜大牛为师 」「 业务代码一样很牛逼 」「 上班太忙没时间学习 」
我之前也是这样的想法,忙时抱怨、闲时迷茫。有一次和同事聊天的时候,他说「 我们大多数的迷茫都是没有计划,大多数的抱怨都是无能的辩解 」。所以我们要做的是「 有计划的利用时间碎片去学习 」。
前面聊了工厂模式、单例模式、适配器模式,这次聊装饰器模式和代理模式。
装饰器模式
装饰器有两个明显的特点:为对象添加新功能
不改变其原有的结构和功能
我们用一个简单的例子来说明:
class Circle {
draw() {
console.log("画一个圆");
}
}
class Decorator {
constructor(circle) {
this.circle = circle;
}
draw() {
this.circle.draw();
this.setRedBorder(circle);
}
setRedBorder(circle) {
console.log("设置红色边框");
}
}
//测试
let circle = new Circle();
circle.draw();
//画一个圆
let dec = new Decorator();
dec.draw();
//画一个圆
//设置红色边框
阮一峰老师在《ES6标准入门》中的第21章提到的修饰器就是我们要讲的装饰器。ES2017将引入这个功能,目前浏览器还不支持,但是babel已经实现转码,需要我们下载babel-plugin-transform-decorators-legacy进行配置。
function testTable(target) {
target.isTestTable = true;
}
@testTable
class TestDemo {}
let test = TestDemo.isTestTable;
console.log(test);
//true
修饰器函数第一个参数就是所要修饰的目标,但是如果要传入多个参数,我们需要进一步封装:
function testTable(isTestTable) {
return (target) => {
target.isTestTable = isTestTable;
};
}
@testTable(true)
class TestDemo {}
如果想添加实例属性,可以通过目标类上的prototype对象来操作:
function minxins(...list) {
return (target) => {
Object.assgin(target.prototype, ...list);
};
}
const Foo = {
foo() {
console.log("foo");
},
};
@minxins(Foo)
class TestDemo {}
let obj = new TestDemo();
obj.foo();
//"foo"
实际开发中,React 与 Redux 库结合使用时常常需要写成下面这样。
class MyReactComponent extends React.Component {}
export default connect( mapStateToProps, mapDispatchToProps)(MyReactComponent);
有了装饰器,我们就可以改写上面的代码了。相对来说,后一种写法看上去更容易理解。
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
修饰器不仅可以修饰类,还可以修饰类的属性 。
class Person {
@readonly
name() {
return `${this.first}${this.last}`;
}
}
function readonly(target, name, descriptor) {
// descriptor 对象原来的值如下
//{
// value: specifiedFunction,
// enumerable : false ,
// configurable: true ,
// writable : true
//};
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, "name", descriptor);
//类似于
Object.defineProperty(Person.prototype, "name", descriptor);
core-decorators
( github.com/jayphelps/core-decorators)是一个第三方模块,提供了几个常见的修饰器,比如readonly、autobind等等,通过它可以更好地理解修饰器。
代理模式
代理模式也很好理解:
使用者无权访问目标对象
中间加代理,通过代理做授权和控制
我们用一个简单的例子来说明:
class ReadImg {
constructor(fileName) {
this.fileName = fileName;
this.loadFromDisk(); //初始化拿去
}
loadFromDisk() {
console.log("loading......" + this.fileName);
}
display() {
console.log("display......" + this.fileName);
}
}
class ProxyImg {
constructor(fileName) {
this.readImg = new ReadImg(fileName);
}
display() {
this.readImg.display();
}
}
//测试
let readImg = new ProxyImg("1.jpg");
readImg.display();
//loading......1.jpg
//display......1.jpg
ES6中提供Proxy来实现代理。在现实中,明星和经纪人就是代理模式很好的事例:
//明星
const star = {
name: "陈XX",
age: 24,
phone: "12312312312",
};
//经纪人
const agent = new Proxy(star, {
get: function (target, key) {
if (key === "phone") {
return "经纪人的手机号";
}
if (key === "price") {
return 1200000;
}
return target[key];
},
set: function (target, key, val) {
if (key === "customPrice") {
if (val < 100000) {
throw new Error("价格太低");
} else {
target[key] = val;
return true;
}
}
}
});
//测试
console.log(agent.name); //陈XX
console.log(agent.age); //24
console.log(agent.phone); //"经纪人的手机号"
console.log(agent.price); //1200000
agent.customPrice = 90000;
console.log("agent.customPrice", agent.customPrice);
代理模式、适配器模式、装饰器模式都很像,都是对原有对象的封装转化等。适配器模式是为了解决不同平台相同功能的问题,而代理模式是解决对受限对象的访问。
适配器模式和代理模式的区别:
简而言之,适配器是输出一个不同(公用)的接口;代理模式是输出一个一模一样的接口。
装饰器模式和代理模式的区别:
装饰器是原有对象的扩展,原有功能直接用;代理模式用的是经过限制后的原有功能。