写在前面
今天学习的是代理模式,依然是按照《大话设计模式》这本书来写的
代理模式:为其他对象提供一种以代理来控制对这个对象的访问。
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
一、实际需求
“娇娇同学,这是有人送你的礼物”,一个男生拿着一束花
“戴笠同学,这是什么意思”娇娇看着这个同班的男同学
“是这样的,我的朋友隔壁三班卓一航,让我代送个礼物”,戴笠有点脸红
“为什么要送我礼物,我不认识他啊”
“他说…他说想和你交个朋友”,戴笠抓抓后脑勺,说话吞吞吐吐。
“不用这样的,我不需要礼物”娇娇显然想拒绝
“别别别,他是我好朋友,他拜托我送你礼物也是下了很大决心的,你看我平常给你讲数学题的份上,就收下吧”戴笠有些着急
“那好吧,今天我对椭圆几何解析还不太懂,你再帮我讲讲”娇娇提出条件后接下礼物
“没问题”戴笠松了口气
…
几天后
“娇娇,这是卓一航送你的花”
…
“娇娇,这是卓一航送你的巧克力”
“我不想要他的礼物了,我不想和他做朋友,我想…我想和你做朋友!”娇娇说
“啊…我不是在做梦吧!”喜从天降,戴笠不敢相信…
“其实我也很喜欢ni…”戴笠抓抓头
从此娇娇和戴笠恋爱了。
“咚!”黑板擦飞过来
数学老师:“上我的课还敢睡觉!”
是不是很狗血,卓一航是为别人做嫁衣,自己不主动,让别人代理谈恋爱
二、使用代理模式来解决这个问题
UML图
IGiveGift接口
package com.fafa.designmode.proxy;
/**
* 送礼物接口
*
* @author Sire
* @version 1.0
* @date 2022-03-10 18:26
*/
public interface IGiveGift {
/**
* 送娃娃
*/
void GiveDolls();
/**
* 送鲜花
*/
void GiveFlowers();
/**
* 送巧克力
*/
void GiveChocolate();
}
追求者
package com.fafa.designmode.proxy.impl;
import com.fafa.designmode.proxy.IGiveGift;
import com.fafa.designmode.proxy.SchoolGirl;
/**
* 追求者
*
* @author Sire
* @version 1.0
* @date 2022-03-10 18:28
*/
public class Pursuer implements IGiveGift {
/**
* 被追求者
*/
SchoolGirl mm;
public Pursuer(SchoolGirl mm) {
this.mm = mm;
}
@Override
public void GiveDolls() {
System.out.println("送给" + mm.getName() + "洋娃娃");
}
@Override
public void GiveFlowers() {
System.out.println("送给" + mm.getName() + "鲜花");
}
@Override
public void GiveChocolate() {
System.out.println("送给" + mm.getName() + "巧克力");
}
}
代理
package com.fafa.designmode.proxy.impl;
import com.fafa.designmode.proxy.IGiveGift;
import com.fafa.designmode.proxy.SchoolGirl;
/**
* 代理
*
* @author Sire
* @version 1.0
* @date 2022-03-10 18:31
*/
public class Proxy implements IGiveGift {
Pursuer pursuer;
public Proxy(SchoolGirl mm) {
// 这里很精妙
pursuer = new Pursuer(mm);
}
@Override
public void GiveDolls() {
pursuer.GiveDolls();
}
@Override
public void GiveFlowers() {
pursuer.GiveFlowers();
}
@Override
public void GiveChocolate() {
pursuer.GiveChocolate();
}
}
被追求的美女
package com.fafa.designmode.proxy;
/**
* 被追求者
*
* @author Sire
* @version 1.0
* @date 2022-03-10 18:29
*/
public class SchoolGirl {
private String name;
public SchoolGirl() {
}
public SchoolGirl(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
客户端
package com.fafa.designmode.proxy;
import com.fafa.designmode.proxy.impl.Proxy;
/**
* 客户端
*
* @author Sire
* @version 1.0
* @date 2022-03-10 18:37
*/
public class ProxyClient {
public static void main(String[] args) {
SchoolGirl mm = new SchoolGirl("娇娇");
Proxy proxy = new Proxy(mm);
proxy.GiveDolls();
proxy.GiveFlowers();
proxy.GiveChocolate();
}
}
三、总结
**意图:**为其他对象提供一种代理以控制对这个对象的访问。
**主要解决:**在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
**何时使用:**想在访问一个类时做一些控制。
**如何解决:**增加中间层。
**关键代码:**实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
**使用场景:**按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。