代理模式
使用者无权访问目标对象
中间加代理,通过代理授权和控制
传统 UML 类图
javascript 中的代理模式
class ReadImg {
constructor(fileName) {
this.fileName = fileName;
this.loadFromDisk();
}
display() {
console.log("display..." + this.fileName);
}
loadFromDisk() {
console.log("loading..." + this.fileName);
}
}
class ProxyImg {
constructor(fileName) {
this.readImg = new ReadImg(fileName);
}
display() {
this.readImg.display();
}
}
// test
let proxyImg = new ProxyImg("1.png");
proxyImg.display();
应用场景
网页代理事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div>
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<a href="#">a5</a>
</div>
<script src="https://cdn.bootcss.com/jQuery/3.3.0/jQuery"></script>
<script>
var div1 = document.getElementById("div1");
div1.addEventListener("clink", function(e) {
var target = e.target;
if (target.nodeName === "A") {
alert(target.innerHTML);
}
});
</script>
</body>
</html>
jQuery
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div>
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<a href="#">a5</a>
</div>
<script src="https://cdn.bootcss.com/jQuery/3.3.0/jQuery"></script>
<script>
$("#div1").click(function() {
// this符合期望
$(this).addClass("red");
});
$("#div1").click(function() {
setTimeout(function() {
// this不符合期望
$(this).addClass("red");
}, 1000);
});
</script>
<script>
// 如下方式解决
$("#div1").click(function() {
// this符合期望
$(this).addClass("red");
});
$("#div1").click(function() {
var _this = this;
setTimeout(function() {
// this符合期望
$(this).addClass("red");
}, 1000);
});
</script>
</body>
</html>
$.proxy
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div>
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
<a href="#">a5</a>
</div>
<script src="https://cdn.bootcss.com/jQuery/3.3.0/jQuery"></script>
<script>
$("#div1").click(function() {
var fn = function() {
$(this).css("background-color", "yellow");
};
fn = $.proxy(fn, this);
setTimeout(fn, 1000);
});
</script>
<script>
// 由上面那个化简而来
$("#div1").click(function() {
fn = $.proxy(function() {
$(this).css("background-color", "yellow");
}, this);
setTimeout(fn, 1000);
});
</script>
<script>
// 由上面那个化简而来
$("#div1").click(function() {
setTimeout(
$.proxy(function() {
$(this).css("background-color", "yellow");
}, this),
1000
);
});
</script>
</body>
</html>
es6 Proxy
明星和经纪人的关系
// 明星
let star = {
name: "张XX",
age: 25,
phone: "13910733521"
};
// 经纪人
let agent = new Proxy(star, {
get: function(target, key) {
if (key === "phone") {
// 返回经纪人自己的手机号
return "18611112222";
}
if (key === "price") {
// 明星不报价,经纪人报价
return 120000;
}
return target[key];
},
set: function(target, key, val) {
if (key === "customPrice") {
if (val < 100000) {
// 最低 10w
throw new Error("价格太低");
} else {
target[key] = val;
return true;
}
}
}
});
// 主办方
console.log(agent.name);
console.log(agent.age);
console.log(agent.phone);
console.log(agent.price);
// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000;
// agent.customPrice = 90000 // 报错:价格太低
console.log("customPrice", agent.customPrice);
设计原则验证
- 代理类和目标类分离,隔离开目标类和使用者
- 符合开放封闭原则
代理模式 VS 适配器模式
- 适配器模式:提供一个不同的接口(如不同版本的插头)
- 代理模式:提供一模一样的接口
代理模式 VS 装饰器模式
- 装饰器模式:拓展功能,原有功能不变且可直接使用
- 代理模式:显示原有功能,但经过限制或阉割之后的