间接的“美”
中国人是一个含蓄的民族,讲究微妙和间接的交流方式。对象间的间接通信也同样是面向对象设计中一条重要的审美观。间接性的通信可以给出较低的耦合关系,较强的合作关系,以及微妙的结构和易于复用的设计架构。
----<<Java与模式>>
1.引言
定义
代理模式的英文叫Proxy或Surrogate。所谓代理就是指一个人或者一个机构代表另一个人或另一个机构采取行动。在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。
意图
为其他对象提供一种代理以控制对这个对象的访问。
2.代理模式的分类
按职责来划分,通常有以下使用场景:
1、远程代理 :为一个位于不同地址空间的对象提供一个局域代表对象。这个不同的地址空间可以在本机上,也可以在另一台机器中,远程代理又叫“大使”(Ambassaor)。
2、虚拟代理 :根据需要创建一个资源消耗较大的对象,使得此对象只在需要时被创建。
3、Copy-on-Write 代理 :虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时才启动。
4、保护(Protect or Access)代理 :控制对一个对象的访问,如果有需要,可以给不同用户提供不同的使用权限。
5、Cache代理:为某一个目标的操作结果提供临时的储存空间,以便多个客户端可以共享这个结果。
6、防火墙(Firewall)代理:保护目标,不让恶意用户接近。
7、同步化(Synchronization)代理 :使几个用户在同时使用一个对象而没有冲突。
8、智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如记录此对象被调用的次数。
3.代理模式的结构
代理模式涉及的角色有:
- 抽象主题角色:声明了真实主题和代理主题的共同接口。这样一来任何使用真实主题的地方都可以使用代理主题。
- 代理主题(Proxy)角色:代理主题角色内部含有一个对真实主题角色的引用。从而可以在任何时候操作真实主体对象;代理主题角色提供一个与真实主题角色相同的接口,以便在任何时候都可以代替真实主题;控制对真实主题的引用,负责在需要的时候创建真实主题对象(或删除真实主题对象);代理主题通常在客户端调用真实主题之前或之后都要执行某个操作,而不是单纯将调用传给真实主题。
-
真实主题角色:定义了代理角色所代表的的真实对象。
实现的类图如下图所示:
4.代理模式的时序
静态的类图不适合反映模式在运行时的特性,时序图则更为形象,下图是代理模式的时序图表示:5.静态代理
(1) 静态代理
由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
(2) 静态代理简单实现
根据上面代理模式的类图,来写一个简单的静态代理的例子。我这儿举一个比较粗糙的例子,假如一个班的同学要向老师交班费,但是都是通过班长把自己的钱转交给老师。这里,班长就是代理学生上交班费,
班长就是学生的代理。
首先,我们创建一个Person接口。这个接口就是学生(被代理类),和班长(代理类)的公共接口,他们都有上交班费的行为。这样,学生上交班费就可以让班长来代理执行。
代码清单一:抽象主题角色的源代码
// 创建一个代理类和真实类的共同接口Person
public interface Person{
// 上交班费
void giveMoney();
}
代码清单二:真实主题源代码
Student类实现Person接口。Student可以具体实施上交班费的动作。
public class Student implements Person {
public Student() {
}
@Override
public void giveMoney() {
System.out.println("上交班费");
}
}
代码清单三:代理主题源代码
/**
* 学生代理类,也实现了Person接口,保存一个学生实体,这样既可以代理学生产生行为
*/
public class StudentsProxy implements Person{
//被代理的学生
Student stu;
public StudentsProxy() {
}
//代理上交班费,调用被代理学生的上交班费行为
public void giveMoney() {
// 调用之前进行操作
preGive();
if(stu == null){
stu = new Student();
}
stu.giveMoney();
// 调用之后进行操作
postGive();
}
public void preGive(){
System.out.println("Before:在give Money之前进行一些操作");
}
public void postGive(){
System.out.println("After:在give Money之后进行一些操作");
}
}
代码清单四:测试源代码
/**
* Created by yucheng on 2018/8/9.
*/
public class StudentProxyDemo {
public static void main(String[] args) {
Person p = new StudentProxy();
p.giveMoney();
}
}
输出结果:
Before Give Money!
上交班费!
After Give Money!
说明:
代理模式最主要的就是有一个公共接口Person,一个具体的类Student,一个代理类StudentProxyDemo,代理类持有具体类的实例,代为执行具体类实例方法。
上面说到,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。这里的间接性就是指不直接调用实际对象的方法,那么我们在代理过程中就可以加上一些其他用途。就如这个例子里的preGive()和postGive()方法。特别是在Spring AOP编程中。在切点(即一个个方法)的前后我们可以进行一系列操作。
这一章,我们主要讲述的是代理模式的基本概念、思想已经应用之静态代理。而下一章,我将继续代理模式之“动态代理”的讲述。敬请期待!
推荐阅读:
设计模式--代理模式(Proxy Pattern)-动态代理