一、引言
二、代理模式的详细介绍
-
远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是本电脑中,也可以在另一台电脑中。最典型的例子就是——客户端调用Web服务或WCF服务。
-
虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得对象只在需要时才会被真正创建。
-
Copy-on-Write代理:虚拟代理的一种,把复制(或者叫克隆)拖延到只有在客户端需要时,才真正采取行动。
-
保护(Protect or Access)代理:控制一个对象的访问,可以给不同的用户提供不同级别的使用权限。
-
防火墙(Firewall)代理:保护目标不让恶意用户接近。
-
智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
-
Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以这些结果。
2.1 定义
2.2 代理模式实现
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
42
43
44
45
46
47
48
49
50
51
52
53
54
|
// 客户端调用
class
Client
{
static
void
Main(
string
[] args)
{
// 创建一个代理对象并发出请求
Person proxy =
new
Friend();
proxy.BuyProduct();
Console.Read();
}
}
// 抽象主题角色
public
abstract
class
Person
{
public
abstract
void
BuyProduct();
}
//真实主题角色
public
class
RealBuyPerson : Person
{
public
override
void
BuyProduct()
{
Console.WriteLine(
"帮我买一个IPhone和一台苹果电脑"
);
}
}
// 代理角色
public
class
Friend:Person
{
// 引用真实主题实例
RealBuyPerson realSubject;
public
override
void
BuyProduct()
{
Console.WriteLine(
"通过代理类访问真实实体对象的方法"
);
if
(realSubject ==
null
)
{
realSubject =
new
RealBuyPerson();
}
this
.PreBuyProduct();
// 调用真实主题方法
realSubject.BuyProduct();
this
.PostBuyProduct();
}
// 代理角色执行的一些操作
public
void
PreBuyProduct()
{
// 可能不知一个朋友叫这位朋友带东西,首先这位出国的朋友要对每一位朋友要带的东西列一个清单等
Console.WriteLine(
"我怕弄糊涂了,需要列一张清单,张三:要带相机,李四:要带Iphone..........."
);
}
// 买完东西之后,代理角色需要针对每位朋友需要的对买来的东西进行分类
public
void
PostBuyProduct()
{
Console.WriteLine(
"终于买完了,现在要对东西分一下,相机是张三的;Iphone是李四的.........."
);
}
}
|
2.3 代理模式的类图结构
三、代理模式的优缺点
-
代理模式能够将调用用于真正被调用的对象隔离,在一定程度上降低了系统的耦合度;
-
代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护。代理对象可以在对目标对象发出请求之前进行一个额外的操作,例如权限检查等。
-
由于在客户端和真实主题之间增加了一个代理对象,所以会造成请求的处理速度变慢
-
实现代理类也需要额外的工作,从而增加了系统的实现复杂度。
四、静态代理与动态代理的比较
(1)静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
(2)静态代理只服务于一个接口。而动态代理可以服务于多个接口。例如上述代码中的静态代理实现的是IUserDao接口,该代理类只服务于该接口,而动态代理HelloWorldProxy实现的是InvocationHandler接口,其不仅仅可以为 HelloWorld接口服务,也可为其他新增接口服务。
(3)静态代理中如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
(4)动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。动态代理中的ClassLoader是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 每次生成动态代理类对象时都需要指定一个类装载器对象.
(5)动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
(1)静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
(2)静态代理只服务于一个接口。而动态代理可以服务于多个接口。例如上述代码中的静态代理实现的是IUserDao接口,该代理类只服务于该接口,而动态代理HelloWorldProxy实现的是InvocationHandler接口,其不仅仅可以为 HelloWorld接口服务,也可为其他新增接口服务。
(3)静态代理中如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
(4)动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。动态代理中的ClassLoader是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。 每次生成动态代理类对象时都需要指定一个类装载器对象.
(5)动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。