Java设计模式之代理模式

来源:互联网 发布:淘宝静物拍摄怎么做 编辑:程序博客网 时间:2024/06/05 10:50

定义:

所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。


生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费。但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的。这点很重要!


上面这个例子,你就是“客户”,票务中心就是“代理角色”,火车站是“真实角色”,卖票称为“抽象角色”!

UML类图:


Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
RealSubject:具体主题角色,也叫被委托角色、被代理角色。是业务逻辑的具体执行者。
Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。(最简单的比如打印日志)

代码实现:

(1)    Subject

/**
* 抽象主题,定义主要功能
*/
public interface Subject {
public void operate();
}

(2)    RealSubject
/**
* 具体主题
*/
public class RealSubject implements Subject{
@Override
public void operate() {
System.out.println("realsubject operatestarted......");
}
}
(3)     Proxy

/**
* 代理类
*/
public class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void operate() {
System.out.println("before operate......");
subject.operate();
System.out.println("after operate......");
}
}
(4)     Client

/**
* 客户
*/
publicclass Client {
/**
* @param args
*/
public static void main(String[] args) {
Subject subject = new RealSubject();
Proxy proxy = new Proxy(subject);
proxy.operate();
}
}

运行结果:     

beforeoperate......
realsubject operate started......
afteroperate......


JDK自带的代理模式实现:
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
动态代理一般用于不允许直接访问某些类、对访问要做特殊处理等场景中。

目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 
Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。

具体实现如下:

创建一个抽象接口:

public interface HelloWorld{
public void sayHelloToWorld();
 
}
创建一个接口的实现类:
public class HelloWorldImpl implements HelloWorld{
 
/**
* @author PeterS
* @date 2016年5月1日
* @param
* @description
*/
@Override
public void sayHelloToWorld() {
System.out.println("Hello World!");
}
}
创建一个继承InvocationHandler接口的约束调用者:
public class HelloWorldHandler implements InvocationHandler {
private Object obj;
/**
* @author PeterS
* @date 2016年5月1日
* @param
* @description
*/
public HelloWorldHandler(Object obj) {
super();
this.obj = obj;
}
 
/**
* @author PeterS
* @date 2016年5月1日
* @param
* @description
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
doBefore();
result = method.invoke(obj, args);
doAfter();
return result;
}
private void doBefore() {
System.out.println("I will do it before the invoke.");
}
private void doAfter() {
System.out.println("I will do it after the invoke.");
}
 
}
接下来测试一下:
public class Test {
 
/**
* @author PeterS
* @date 2016年5月1日
* @param
* @description
*/
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorldImpl();
InvocationHandler invocationHandler = new HelloWorldHandler(helloWorld);
//创建动态代理对象
HelloWorld proxy = (HelloWorld)Proxy.newProxyInstance(helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), invocationHandler);
proxy.sayHelloToWorld();
}
 
}
输出结果为:
I will do it before the invoke.
Hello World
I will do it after the invoke.

 代理模式的应用形式

(1) 远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

(2) 虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。

(3) 写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。

(4) 保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限

(5) 缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。

(6) 防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。

(7) 同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。

(8) 智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

(9) 复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。

0 0