GoF设计模式(十二):Proxy Pattern 代理模式

Proxy Pattern代理模式,可以说其是最简单易懂的一种结构型设计模式

abstract.jpeg

模式思想

代理模式,其实大家不论是在日常生活还是软件开发领域见的都是比较多的。典型地,我们买商品一般不会直接去工厂去买,而是和商店这个中间商来打交道的。而这其实就体现了代理模式的精神内涵,即当client由于某种原因(存在困难、麻烦等原因)不便于直接使用某个对象时,可以通过使用代理者来间接的使用、访问某个对象。这样做的好处,一方面可以方便client使用,另一方面可以通过代理者可以增强对象原有的功能、行为,即所谓的AOP。该模式涉及到的角色也很少

  • 抽象角色 : 为了保证代理对象与真实角色接口统一,故需一个抽象角色。用于定义共有的方法。即本文例子中的Sell接口
  • 真实角色(即被代理角色) : 其即是被代理的角色。由于其才是真正执行相关操作的,故又被称作真实角色。即本文例子中的Apple类
  • 代理角色 : 其是对真实角色的代理,通过内部持有真实角色实例进行请求转发,完成真正的行为调用。还可以根据实际需要(比如日志、安全、缓存等需求)来拓展、增强真实角色的行为。即本文例子中的AppleStore类

实现

现在,我们使用Java实现该模式来帮助人民群众更好的理解。首先定义一个抽象角色,即卖数码产品的Sell接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 抽象角色: 卖数码产品
*/
public interface Sell {
/**
* 卖手机
*/
void sellPhone();

/**
* 卖电脑
*/
void sellPc();
}

现在,我们有一个被代理对象苹果公司Apple类,其可以从工厂直接出售产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 真实角色(即被代理角色): 苹果公司
*/
public class Apple implements Sell {
/**
* 卖苹果手机
*/
@Override
public void sellPhone() {
System.out.println("Apple: Sell iPhone SE");
}

/**
* 卖苹果电脑
*/
@Override
public void sellPc() {
System.out.println("Apple: Sell MacBook Pro");
}
}

现在,我们为了方便人民群众购买苹果设备,提供了一个代理者——苹果经销商AppleStore类。可以看到其内部持有了Apple实例进行请求转发。与此同时,通过代理者实现了对原有功能的增强(makeAd、record方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 代理角色:苹果经销商
*/
public class AppleStore implements Sell{
/**
* 内部持有 真实角色(即被代理角色)苹果公司 的 实例,以进行请求转发完成真正的行为
*/
private Apple apple;

public AppleStore(Apple apple) {
this.apple = apple;
}

@Override
public void sellPhone() {
makeAd();
apple.sellPhone();
record();
}

@Override
public void sellPc() {
makeAd();
apple.sellPc();
record();
}

/**
* 售前:宣传、吹牛逼
*/
private void makeAd() {
System.out.println("苹果的产品设计优雅、使用便捷");
}

/**
* 售后:记账、更新库存
*/
private void record() {
System.out.println("更新销售记录、更新库存数");
}
}

至此,我们的代理模式就已经完成了,现在来看看如何使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Proxy Pattern 代理模式 Demo
*/
public class ProxyPatternDemo {
public static void main(String[] args) {
// 创建 真实角色(即被代理角色) 苹果公司 实例
Apple apple = new Apple();

// 创建 代理角色 实例
Sell appleStore = new AppleStore(apple);

// 通过代理角色 调用方法
appleStore.sellPhone();
// 通过代理角色 调用方法
appleStore.sellPc();
}
}

测试结果如下,符合预期

figure1.png

准确来说,这里我们所实现的代理模式实际上是静态代理,即代理角色需要提前编写好,在运行前就被确定下来了。而在很多框架实现中更多的是采用动态代理的方式,即代理类是在运行期时动态生成的

参考文献

  1. Head First 设计模式 弗里曼著
0%