代理模式 使用者無權訪問目標對象 中間加代理,通過代理授權和控制 傳統 UML 類圖 JavaScript 中的代理模式 應用場景 網頁代理事件 jQuery \$.proxy es6 Proxy 明星和經紀人的關係 設計原則驗證 代理類和目標類分離,隔離開目標類和使用者 符合開放封閉原則 代理模式 ...
代理模式
使用者無權訪問目標對象
中間加代理,通過代理授權和控制
傳統 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 裝飾器模式
- 裝飾器模式:拓展功能,原有功能不變且可直接使用
- 代理模式:顯示原有功能,但經過限制或閹割之後的