代理模式
1、动机
面向对象的系统中某些对象由于某种原因(创建开销大,某些操作需要安全控制,或者要进程外的访问等),不能或者不想直接访问使用者、会给系统带来很多麻烦。
如何在不是去透明操作对象的同时管理控制这些对象特有的复杂性?--->增加一层间接层,通过一个代理对象间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。
2、定义
- 代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
- 引入一个新的代理对象
- 代理对象在客户端对象和目标对象之间起到中介的作用。
- 可以去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务。
3、结构
- Subject(抽象主题角色):声明代理主题和真实角色的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
- Proxy(代理主题角色): 通常,在代理主题角色中,客户端在调用所引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯地调用真实主题对象中的操作。
- 它包含了对真实主题的引用, 从而可以在任何时候操作真实主题对象;
- 提供了一个与真实主题角色相同的接口,以便在任何时候都可以代替真实主题;
- 代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实主题对象,并对真实主题对象的使用加以约束。
4、TS案例
//接口,定义方法
interface ICalc {
calc(num1: number, num2: number): number;
}
// 两个代理类
class Npc1 implements ICalc {
calc(num1: number, num2: number) {
return num1 + num2;
}
}
class Npc2 implements ICalc {
calc(num1: number, num2: number) {
return num1 - num2;
}
}
class Person {
// 代理
delegate!: ICalc;//声明中添加了非空断言运算符(!),因为在构造函数中没有初始化 delegate 属性
// 执行任务
getNum(num1: number, num2: number) {
const num = this.delegate.calc(num1, num2);
return num
}
}
const person = new Person();
// 设定一个代理
person.delegate = new Npc1();
console.log(person.getNum(3, 4)); // 7
person.delegate = new Npc2();
console.log(person.getNum(3, 4)); // -1
5、补充
直接使用某些对象带来麻烦、复杂问题---->增加一层间接层 Proxy不一定要求保持接口完整地一致性,只要能实现间接控制,有时候损及一些透明性是可以接受的。
- 代理模式的主要优点:
- 是能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
- 系统具有较好的灵活性和可扩展性,客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则。
- 其主要缺点是
- 有些类型的代理模式可能会造成请求的处理速度变慢;
- 实现代理模式需要一些额外的工作,而且有些代理模式的实现过程较为杂。