代理模式-Proxy

Proxy 介绍

  • 使用者无权访问目标对象

  • 中间加代理,通过代理做授权和控制

Proxy 示例 & UML

➊ 上网翻墙

➋ 公司内网代理

➌ 明星经纪人

Proxy 代码

class RealImg {
	constructor(fileName) {
		this.fileName = fileName;
		this.loadFromDisk(); // 初始化即从硬盘中加载,模拟
	}
	display() {
        console.log('display...' + this.fileName);
	}
	loadFromDisk() {
		console.log('loading...' + this.fileName)
	}
}

class ProxyImg {
	constructor(fileName) {
		this.realImg = new RealImg(fileName);
	}
	display() {
		this.realImg.display();
	}
}

// 测试
let proxyImg = new ProxyImg('1.png');
proxyImg.display();

Proxy 场景

➊ 网页事件代理

➋ jq 的 proxy

➌ ES6 Proxy

➍ 浏览器跨域

网页事件代理-Web Event

<div id="demo">
	<a href="#">a1</a>
	<a href="#">a2</a>
	<a href="#">a3</a>
	<a href="#">a4</a>
</div>
<button>点击增加一个 a 标签</button>

<script>
	var demo = document.getElementById("demo");
	demo.addEventListener('click', function(e) {
		var target = e.target;
		if (target.nodeName === 'A') {
			alert(target.innerHTML);
		}
	})
</script>

ES6 Proxy

// 明星
let star = {
	name: '张XXX',
	age: 25,
	phone: '18300001111'
}

// 经纪人
let agent = new Proxy(star, {
	get: function(target,key) {
		if (key === 'phone') {
			// 返回经纪人自己的手机号
			return '18312341234'
		}
		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;
console.log(agent.customPrice);

Proxy 设计原则验证

  • 代理类和目标类分离,隔离开目标类和使用者

  • 符合开放封闭原则

代理 & 适配器 & 装饰器 对比-Contrast

代理模式 VS 适配器模式

适配器模式:提供一个不同的接口(如不同版本的插头)

代理模式:提供一模一样的接口

代理模式 VS 装饰器模式

装饰器模式:扩展功能,原有功能不变且可直接使用

代理模式:显示原有功能,但是经过限制或者阉割之后的