代理模式
本篇装饰模式,借鉴参考《大话设计模式》中的例子,使用了 Java 来进行简单的实现。
小明是小红隔壁班的,小明通过小红的同班同学小王来给小红送礼物。
mermaid的类图在手机上显示不友好,推荐使用电脑进行阅读。也可以克隆项目到本地,在 idea 中安装mermaid插件进行阅读。项目地址:design-patterns ,将会持续更新各种模式的应用,以及后续的实际案例应用。
简单实现
没有代理的实现
追求者类
public class Pursuer {
Pursued mm;
public Pursuer(Pursued mm) {
this.mm = mm;
}
public void giveDoll() {
System.out.println(mm.getName() + " 送你洋娃娃");
}
public void giveFlowers() {
System.out.println(mm.getName() + " 送你鲜花");
}
public void giveChocolate() {
System.out.println(mm.getName() + " 送你巧克力");
}
}
被追求者类
public class Pursued {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
客户端
public class Client {
public static void main(String[] args) {
Pursued xh = new Pursued();
xh.setName("小红");
Pursuer xm = new Pursuer(xh);
xm.giveChocolate();
xm.giveDoll();
xm.giveFlowers();
System.out.println();
}
}
观察一下代码,Pursuer xm = new Pursuer(xh); 这些写的话就等于小明亲自送礼物给小红了,不符合我们的题目要求。
只有代理的实现
代理类
public class Proxy {
Pursued mm;
public Proxy(Pursued mm) {
this.mm = mm;
}
public void giveDoll() {
System.out.println(mm.getName() + " 送你洋娃娃");
}
public void giveFlowers() {
System.out.println(mm.getName() + " 送你鲜花");
}
public void giveChocolate() {
System.out.println(mm.getName() + " 送你巧克力");
}
}
被追求者类
public class Pursued {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
客户端
public class Client {
public static void main(String[] args) {
Pursued xh = new Pursued();
xh.setName("小红");
Proxy xw = new Proxy(xh);
xw.giveChocolate();
xw.giveDoll();
xw.giveFlowers();
System.out.println();
}
}
观察上面的代码,只有代理的实现中没有了小明的概念,相当于小王直接把礼物送给了小红,但礼物其实是小明
买的。由此可以想到,代码的逻辑应该为 Pursuer(追求者) 通过 Proxy(代理者) 送给 Pursued(被追求者) 礼物,这才应该是合理的,可是应该怎么做呢?
再仔细观察一下,Pursuer(追求者) 和 Proxy(代理者) 其实都用送礼物的行为,只不过 Proxy(代理者)
送的礼物是 Pursuer(追求者) 买的,实质上应该是 Pursuer(追求者) 送的礼物。那既然两者都有相同的方法,那就意味着他们都可以实现相同的接口了。
改造代理模式
代理接口
public interface IGiveGift {
/**
* 送洋娃娃
*/
void giveDoll();
/**
* 送花
*/
void giveFlowers();
/**
* 送巧克力
*/
void giveChocolate();
}
追求者
public class Pursuer implements IGiveGift {
Pursued mm;
public Pursuer(Pursued pursued) {
mm = pursued;
}
@Override
public void giveDoll() {
System.out.println(mm.getName() + " 送你洋娃娃");
}
@Override
public void giveFlowers() {
System.out.println(mm.getName() + " 送你鲜花");
}
@Override
public void giveChocolate() {
System.out.println(mm.getName() + " 送你巧克力");
}
}
被追求者
public class Pursued {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
代理类
public class Proxy implements IGiveGift {
Pursuer gg;
public Proxy(Pursued mm) {
gg = new Pursuer(mm);
}
@Override
public void giveDoll() {
gg.giveDoll();
}
@Override
public void giveFlowers() {
gg.giveFlowers();
}
@Override
public void giveChocolate() {
gg.giveChocolate();
}
}
客户端
public class Client {
public static void main(String[] args) {
Pursued xh = new Pursued();
xh.setName("小红");
Proxy proxy = new Proxy(xh);
proxy.giveChocolate();
proxy.giveDoll();
proxy.giveFlowers();
System.out.println();
}
}
在客户端代码中可以看到,小红收到的礼物其实是小明通过代理(小王)送出的了,而且小红不认识追求她的人,效果已经达到了。
示例结构图
classDiagram
direction RL
代理 ..|> 送礼物
追求者 ..|> 送礼物
代理 --> 追求者
class 送礼物 {
<<interface>>
+ 送洋娃娃()
+ 送鲜花()
+ 送巧克力()
}
class 代理 {
+ 送洋娃娃()
+ 送鲜花()
+ 送巧克力()
}
class 追求者 {
+ 送洋娃娃()
+ 送鲜花()
+ 送巧克力()
}
构造模式结构图
classDiagram
direction BT
Client --> Subject
RealSubject --|> Subject
Proxy --|> Subject
Proxy --> RealSubject: -realSubject
note for Subject "Subject 类,定义了 RealSubject 和 Proxy 的共用接口\n这样就在任何使用 RealSubject 的地方都可以使用 Proxy"
class Subject {
<<abstract>>
+ request()
}
note for RealSubject "RealSubject 类,定义 Proxy 所代表的真实实体"
class RealSubject {
+ request()
}
note for Proxy "Proxy 类,保存一个引用使得代理可以访问实体,并提供一个\n与 Subject 的接口相同的接口,这样代理就可以用来替代实体"
class Proxy {
+ request()
}
class Client {
}
Subject 类,定义了 RealSubject 和 Proxy 的共用接口,这样就在任何使用 RealSubject 的地方都可以使用 Proxy。
public interface Subject {
void giveDoll();
}
RealSubject 类,定义 Proxy 所代表的真实实体。
public class RealSubject extends Subject {
@Override
public void request() {
System.out.println("真实的请求");
}
}
Proxy 类,保存一个引用,使得代理可以访问实体,并提供一个与 Subject 的接口相同的接口,这样代理就可以用来替代实体。
public class Proxy extends Subject {
RealSubject realSubject;
@Override
public void Request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
}
}
优缺点
优点
-
简化客户端的访问。代理对象可以隐藏原始对象的复杂性,使得客户端可以更加简单地访问原始对象。
-
降低系统的耦合度。代理对象与原始对象之间进行解耦,使得系统更加灵活,可扩展性更高。
-
代理对象可以控制对原始对象的访问。代理对象可以对客户端的请求进行过滤和验证,保证原始对象的安全性。
-
提高系统的性能。代理对象可以在访问原始对象之前进行一些预处理,从而提高系统的性能。
缺点
-
增加系统的复杂性。代理模式需要增加额外的代理类,使得系统的结构变得更加复杂。
-
增加系统的开销。代理模式需要额外的开销来处理请求和响应,从而增加了系统的开销。
-
可能降低系统的响应速度。代理对象需要额外的时间来处理请求和响应,从而可能降低系统的响应速度。
适用场景:
-
远程代理。当原始对象位于远程服务器上时,可以使用代理模式实现客户端与服务器之间的通信。
-
虚拟代理。当创建原始对象需要很长时间时,可以使用代理模式实现延迟加载,即在需要时才创建原始对象。
-
安全代理。当需要对原始对象进行安全控制时,可以使用代理模式实现访问控制。
-
智能代理。当需要在访问原始对象时添加额外的逻辑处理时,可以使用代理模式实现智能代理。