代理模式(Proxy Pattern)
概述
代理是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。
分类
- 远程代理(Remote Proxy):控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
- 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
- 保护代理(Protection Proxy):按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
- 智能代理(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作:记录对象的引用次数;当第一次引用一个对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
应用实例
- Windows 里面的快捷方式
- 猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类
- 买火车票不一定在火车站买,也可以去代售点
- 代购
- 一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制
- 信用卡是银行账户的代理,银行账户则是一大捆现金的代理。它们都实现了同样的接口,均可用于进行支付。消费者会非常满意,因为不必随身携带大量现金;商店老板同样会十分高兴,因为交易收入能以电子化的方式进入商店的银行账户中,无需担心存款时出现现金丢失或被抢劫的情况
- Spring AOP
优点
-
职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
-
高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
-
智能化
基本结构
- 服务接口(Service Interface)声明了服务接口。代理必须遵循该接口才能伪装成服务对象。
- 服务(Service)类提供了一些实用的业务逻辑。
- 代理(Proxy)类包含一个指向服务对象的引用成员变量。代理完成其任务(例如延迟初始化、记录日志、访问控制和缓存等)后会将请求传递给服务对象。通常情况下,代理会对其服务对象的整个生命周期进行管理。
- 客户端(Client) 能通过同一接口与服务或代理进行交互,所以你可在一切需要服务对象的代码中使用代理。
静态代理【重点】
概述
静态代理是指预先确定了代理与被代理者的关系,即代理类与被代理类的依赖关系在编译期间就确定了。
静态代理又分为强制代理和普通代理。普通代理的要求就是客户端只能访问代理角色,而不能访问真实角色;强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。
案例一
描述
永强的公司老板突然在发工资的前一天带着小姨子跑路了,可怜的永强一身房贷,被迫提起劳动仲裁,劳动局就会为其指派一位代理律师全权负责永强的仲裁事宜。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理永强。
案例代码
Interface
// 诉讼接口
public interface LawSuit {
// 提起诉讼
void submit();
// 法庭辩护
void defend();
}
Service
// 诉讼当事人(原告)
public class Parties implements LawSuit {
@Override
public void submit() {
System.out.println("老板欠薪跑路,证据确凿!!!");
}
@Override
public void defend() {
System.out.println("铁证如山,欠债还钱");
}
}
Proxy
// 代理律师类,全权负责案件的代理
public class Lawyer implements LawSuit {
// 包含一个被代理的对象
private final LawSuit lawSuit;
// 通过构造方法传递被代理对象
public Lawyer(LawSuit lawSuit) {
this.lawSuit = lawSuit;
}
@Override
public void submit() {
// 搜集证据
this.gatherEvidence();
// 提起诉讼
this.lawSuit.submit();
}
@Override
public void defend() {
// 法庭辩护
this.lawSuit.defend();
// 交换意见
this.compareNotes();
}
// 搜集证据(属于增强的方法)
private void gatherEvidence() {
System.out.println("搜集证据");
}
// 交换意见(属于增强的方法)
private void compareNotes() {
System.out.println("与审判长、审判员交换意见,被告如果不服,代其上诉或申诉");
}
}
Client
// 开庭
public class Court {
@Test
public void testLawSuit() {
// 当事人安排上
Parties parties = new Parties();
// 当事人的代理律师安排上
Lawyer lawyer = new Lawyer(parties);
// 代理律师进行提起诉讼以及法庭辩护
lawyer.submit();
lawyer.defend();
}
}
案例二
描述
玉田是个游戏死忠粉,每天最大的乐趣就是在游戏里大杀四方,但是游戏打时间长了,腰酸背痛、眼睛干涩、手臂酸麻,等等,也就是网络成瘾综合症都出来了。玉田想玩游戏,但又不想碰触到游戏中的烦恼,如何解决呢?有办法,现在游戏代练的公司非常多,于是玉田把自己的账号交给代练人员,由他们去帮着升级,去打怪,非常好的想法。游戏代练者,它也不能有作弊的方法(开挂),也只能手动打怪,这个时候,玉田的代练者就上着他的号,扮演着他的角色在游戏里继续大杀四方。
案例代码
Interface
// 游戏接口
public interface GamePlay {
// 登录
void login();