设计模式(11)之代理模式
2016-04-24 13:05
197 查看
1. 什么是代理模式
Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。 所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
2. 代理模式的结构
3. 代理模式的角色和职责
subject(抽象主题角色):
真实主题与代理主题的共同接口。
RealSubject(真实主题角色):
定义了代理角色所代表的真实对象。
Proxy(代理主题角色):
含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
下面我举一个 “卖书” 的例子。 首先,该例子中 “卖书”是一个主题觉角色,所以,我们首先定义一个接口(或抽象类)来表示这个主题角色。
然后是具体的主题角色,即实现了”卖书”接口的实现类。
其实这样,我们就可以”卖书”了,在主方法中,实例化一个RealSubject对象,然后调用sellBook方法就可以实现”卖书”这个功能了。但是,有的时候,为了促销,有时候打折,有时候送代金券,也就是说在”卖书”前后我们还需要做一定的处理的时候,这时候怎么办?将这些操作写到sellBook方法中,显然是不合适的。将这些操作抽取出来一个方法放在RealSubject对象中,好像也不太合适,如果还有其他的RealSubject也实现了Subject接口了呢,那不得再写一遍这些操作?
所以,这里我们再定义一个代理类。
代理类的作用就是在”卖书”这个操作进行之前或之后,我们可以自定义一些自己的操作。这样RealSubject的”卖书”的权利就转交到SubjectProxy这个代理的手中,这个书具体怎么卖,但是核心的sellBook还是调用的RealSubject中的sellBook方法。
言多必失,看代码就一目了然了。
主类中的代码:
4. 动态代理
InvocationHandler 接口
invoke方法
Proxy.newProxyInstance();
什么是动态代理?
前面我们是不是写了一个SubjectProxy这个代理类,该代理类的作用就是在sellBook前后做一些自定义的操作,但是你发现没有,这些个操作都是写在这个代理类中的,如果这些自定义的操作以后需要更改怎么办?去修改SubjectProxy中的代码吗?我咋感觉不太好呢,这扩展性也太差了吧。
所以,聪明的程序员们发明了 动态代理这个东东。
动态代理,我们不需要自己手动实现代理类,即在我们的程序中没有具体的代理类,我们只需要提供自定义的操作即可,在Java中我们只要自定义一个处理类,实现InvocationHandler这个接口,该接口中定义了一个方法,没错,该方法就是实现我们的一些自定义的操作。
现在我们看一下这个自定义事件处理类,RealSubject.java和Subject.java中的代码不变。
在该事件处理类中,实现了InvocationHandler接口中的invoke方法,在该方法中自定义了一些操作。但是,你会法线,他并么有调用RealSubject中的sellBook方法,是的,这里他确实没有调用。想知道为什么吗?我想大概是为了可扩展性吧。
你想想呀,现在Subject中只定义了一个sellBook的方法,改名这个接口又加了一个sellXXX的方法了,如果这个事件处理类中写死了的话,那么Subject这个接口改了,这个事件处理类的代码是不是也要修改,那也太不灵活了吧。所以这里使用了Java中的反射技术。不管你Subject中的接口怎么变,只要你的实现类RealSubject跟着变就是了,我事件处理类最终还不是调用你的实现类RealSubject类中的一个方法就完事了。所以,调用Subject中sellBook方法的操作我们写在客户端比较合适,事件处理类中只包括我们自己要做的处理,这样,只要我们自己的处理不变,那么这个事件处理程序类就不需要做任何改变。
现在我们看一下,主类中的代码:
Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。 所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。
2. 代理模式的结构
3. 代理模式的角色和职责
subject(抽象主题角色):
真实主题与代理主题的共同接口。
RealSubject(真实主题角色):
定义了代理角色所代表的真实对象。
Proxy(代理主题角色):
含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
下面我举一个 “卖书” 的例子。 首先,该例子中 “卖书”是一个主题觉角色,所以,我们首先定义一个接口(或抽象类)来表示这个主题角色。
//Subject.java public interface Subject { public void sellBook(); }
然后是具体的主题角色,即实现了”卖书”接口的实现类。
//RealSubject.java public class RealSubject implements Subject{ public void sellBook() { System.out.println("金瓶梅甩卖啦。。。"); } }
其实这样,我们就可以”卖书”了,在主方法中,实例化一个RealSubject对象,然后调用sellBook方法就可以实现”卖书”这个功能了。但是,有的时候,为了促销,有时候打折,有时候送代金券,也就是说在”卖书”前后我们还需要做一定的处理的时候,这时候怎么办?将这些操作写到sellBook方法中,显然是不合适的。将这些操作抽取出来一个方法放在RealSubject对象中,好像也不太合适,如果还有其他的RealSubject也实现了Subject接口了呢,那不得再写一遍这些操作?
所以,这里我们再定义一个代理类。
代理类的作用就是在”卖书”这个操作进行之前或之后,我们可以自定义一些自己的操作。这样RealSubject的”卖书”的权利就转交到SubjectProxy这个代理的手中,这个书具体怎么卖,但是核心的sellBook还是调用的RealSubject中的sellBook方法。
言多必失,看代码就一目了然了。
//RealSubjectProxy.java public class SubjectProxy implements Subject{ //将RealSubject作为代理的成员变量,因为最终还是要调用RealSubject对象中的sellBook方法的。 private RealSubject realSubject; public void setRealSubject(RealSubject realSubject) { this.realSubject = realSubject; } private void dazhe(){ System.out.println("买金瓶梅打折."); } private void give(){ System.out.println("买金瓶梅送连环画"); } @Override public void sellBook() { //在真正sellBook前后,我们可以做一些自己的处理。 dazhe(); this.realSubject.sellBook(); give(); } }
主类中的代码:
//MainClass.java public class MainClass { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); SubjectProxy proxy = new SubjectProxy(); proxy.setRealSubject(realSubject); proxy.sellBook(); } }
4. 动态代理
InvocationHandler 接口
invoke方法
Proxy.newProxyInstance();
什么是动态代理?
前面我们是不是写了一个SubjectProxy这个代理类,该代理类的作用就是在sellBook前后做一些自定义的操作,但是你发现没有,这些个操作都是写在这个代理类中的,如果这些自定义的操作以后需要更改怎么办?去修改SubjectProxy中的代码吗?我咋感觉不太好呢,这扩展性也太差了吧。
所以,聪明的程序员们发明了 动态代理这个东东。
动态代理,我们不需要自己手动实现代理类,即在我们的程序中没有具体的代理类,我们只需要提供自定义的操作即可,在Java中我们只要自定义一个处理类,实现InvocationHandler这个接口,该接口中定义了一个方法,没错,该方法就是实现我们的一些自定义的操作。
现在我们看一下这个自定义事件处理类,RealSubject.java和Subject.java中的代码不变。
//MyHandle.java package com.zemo.wj; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyHandler implements InvocationHandler{ private RealSubject realSubject; public void setRealSubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; dazhe(); result = method.invoke(realSubject, args); give(); return result; } private void dazhe(){ System.out.println("买金瓶梅打折."); } private void give(){ System.out.println("买金瓶梅送连环画"); } }
在该事件处理类中,实现了InvocationHandler接口中的invoke方法,在该方法中自定义了一些操作。但是,你会法线,他并么有调用RealSubject中的sellBook方法,是的,这里他确实没有调用。想知道为什么吗?我想大概是为了可扩展性吧。
你想想呀,现在Subject中只定义了一个sellBook的方法,改名这个接口又加了一个sellXXX的方法了,如果这个事件处理类中写死了的话,那么Subject这个接口改了,这个事件处理类的代码是不是也要修改,那也太不灵活了吧。所以这里使用了Java中的反射技术。不管你Subject中的接口怎么变,只要你的实现类RealSubject跟着变就是了,我事件处理类最终还不是调用你的实现类RealSubject类中的一个方法就完事了。所以,调用Subject中sellBook方法的操作我们写在客户端比较合适,事件处理类中只包括我们自己要做的处理,这样,只要我们自己的处理不变,那么这个事件处理程序类就不需要做任何改变。
现在我们看一下,主类中的代码:
//MainClass.java package com.zemo.wj; import java.lang.reflect.Proxy; public class MainClass { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); MyHandler handler = new MyHandler(); handler.setRealSubject(realSubject); Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), realSubject.getClass().getInterfaces(), handler); proxySubject.sellBook(); } }
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解
- 实例解析C#设计模式编程中简单工厂模式的使用
- 详解C#设计模式编程中生成器模式的使用