JavaScript 设计模式----代理模式

1. 代理模式

1.1 代理模式介绍

  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制

1.2 代理模式类图

  • 传统 UML 类图
    在这里插入图片描述
  • 简化后的 UML 类图
    在这里插入图片描述

1.3 代理模式演示

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.realImg = new ReadImg(fileName) // 实例化 ReadImg 类
	}
	display() {
    
    
		this.realImg.display()
	}
}

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

1.4 代理模式场景

1.4.1 网页事件代理
<div id="div1">
  <a href="#">a1</a>
  <a href="#">a2</a>
  <a href="#">a3</a>
  <a href="#">a4</a>
</div>
<button>点击增加一个 a 标签</button>
<script>
    var div1 = document.getElementById('div1')
    div1.addEventListener('click', function (e) {
     
     
        var target = e.target
        if (e.nodeName === 'A') {
     
     
            alert(target.innerHTML)
        }
    })
</script>
1.4.2 jQuery 中 $.proxy
$('#div1').click(function () {
    
     
    // this 符合期望
    $(this).addClass('red')
    
})
$('#div1').click(function () {
    
     
    setTimeout(function () {
    
    
        // this 不符合期望
        $(this).addClass('red')
    }, 1000)
});
// 可以用如下方式解决
$('#div1').click(function () {
    
     
    var _this = this
    setTimeout(function () {
    
    
        // _this 符合期望
        $(_this).addClass('red');
    }, 1000)
});
// 但推荐使用 $.proxy 解决,这样就少定义一个变量
$('#div1').click(function () {
    
     
    setTimeout($.proxy(function () {
    
    
        // this 符合期望
        $(this).addClass('red')
    }, this), 1000)
});
1.4.3 ES6 中 Proxy
// 明星
let star = {
    
    
    name: 'xxx',
    age: 24,
    phone: 'star: 13900001111'
}

// 经纪人
let agent = new Proxy(star, {
    
    
    get: function (target, key) {
    
     // 代理的接口必须和原生的一样
        if (key === 'phone') {
    
    
            // 返回经纪人自己的电话
            return 'agent: 16899992222'
        }
        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 = 90000
console.log('agent.customPrice', agent.customPrice);

1.5 代理模式设计原则验证

  • 代理类和目标类分离,隔离开目标类和使用者
  • 符合开放封闭原则

1.6 代理模式 VS 适配器模式

  • 适配器模式
    • 提供一个不同的接口(如不同版本的插头)
    • 使用者想去使用目标类
    • 但是目标类老旧或格式不一样,不能用
    • 需要加一个第三方的适配器配置一下,进行格式的转换
    • 所以要提供一个不一样的接口
  • 代理模式
    • 提供一模一样的接口
    • 使用者无权使用目标类
    • 但是需要使用目标类的权限
    • 就需要代理,要和目标类一样的接口

1.7 代理模式 VS 装饰器模式

  • 装饰器模式
    • 扩展功能,原有功能不变且可直接使用
    • 扩展功能与原有功能并不冲突
  • 代理模式
    • 显示原有功能,但是经过限制或者阉割之后的

猜你喜欢

转载自blog.csdn.net/qq_43645678/article/details/114543029