1.代理模式定义:
装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;
代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用;
装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,并不提供对象本身的增强功能
代理模式一般涉及到的角色
抽象角色:声明真实对象和代理对象的共同接口。
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。
同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
1 public class Daili { 2 3 public static void main(String[] args) { 4 5 SellProxy proxy = new SellProxy(new SellFactoryB()); 6 proxy.doSell(); 7 proxy = new SellProxy(new SellFactoryB()); 8 proxy.doSell(); 9 10 } 11 12 } 13 14 interface Sell { 15 16 public void sell(); 17 } 18 19 class SellFactoryB implements Sell { 20 21 public void sell() { 22 System.out.println("B开发商卖房子给你"); 23 24 } 25 } 26 27 class SellFactoryC implements Sell { 28 29 public void sell() { 30 System.out.println("C开发商卖房子给你"); 31 32 } 33 } 34 35 class SellProxy { 36 private Sell sell; 37 38 public SellProxy(Sell sell) { 39 40 this.sell = sell; 41 } 42 43 public void doSell() { 44 System.out.println("代理商帮你买房啦"); 45 sell.sell(); 46 System.out.println("代理商帮你处理其他事情"); 47 } 48 49 }
上面的例子,其实有一定的歧义,因为这有点像策略模式了,另外你可能会有疑惑,既然你都可以得到SellFactoryB对象了,为什么还需要依托
SellProxy对象。为了更好的表示代理模式,我们举个形象的例子。情景如下:假如我们要买一台华硕笔记本,那我们不能跑到厂家直接要一台是吧,一般都是代理商哪里买一台,而代理商可以拿到
内部价,然后按一定比例提价后卖给你,当然了,为了促销,代理商会送你一些噱头,比如鼠标,键盘之类的,最后我们愉快的买下了笔记本
1 interface SellComputer{ 2 3 public double sell(); 4 } 5 class AsusComputer implements SellComputer{ 6 7 public double sell(){ 8 9 10 return 7999; 11 } 12 13 } 14 15 class AsusComputerProxy implements SellComputer{ 16 private SellComputer sellComputer; 17 18 public AsusComputerProxy(){ 19 sellComputer =new AsusComputer(); 20 21 } 22 public double sell(){ 23 beforeSell(); 24 double price= sellComputer.sell(); 25 double sellPrice=price*1.2; 26 afterSell(); 27 return sellPrice; 28 } 29 30 31 private void beforeSell(){ 32 33 System.out.println("送你一个键盘"); 34 } 35 private void afterSell(){ 36 37 System.out.println("帮你保修一年"); 38 } 39 40 }
调用过程
SellComputer computer=new AsusComputerProxy(); System.out.println("愉快的从代理商买到了华硕笔记本,价钱为:"+computer.sell());
执行结果:
送你一个键盘
帮你保修一年
愉快的从代理商买到了华硕笔记本,价钱为:9598.8
静态代理存在的问题:
实际使用时,一个真实角色必须对应一个代理角色,但如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。
动态代理
具体有如下四步骤:
通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
对上述的笔记本代理商我们进行改造了,实际生活中不仅仅有华硕笔记本,还有联想,IBM等等,假如有20个代理商,我们是不是要写20个代理类呢,实际上,我们可以通过动态代理模式来解决
1 //新增被代理对象 IBM品牌 2 class IbmComputer implements SellComputer{ 3 public double sell(){ 4 return 9999; 5 } 6 7 }
动态处理类
1 class MyHandler implements InvocationHandler { 2 private Object proxyObj; 3 4 public MyHandler(Object proxyObj) { 5 6 this.proxyObj = proxyObj; 7 } 8 public Object invoke(Object proxy, Method method, Object[] args) 9 throws Throwable { 10 System.out.println("动态调用方法:" + method.getName()); 11 Object md = method.invoke(proxyObj); 12 return md; 13 } 14 15 }
调用过程
1 IbmComputer ibmComputer=new IbmComputer(); 2 Class cls =computer.getClass(); 3 MyHandler handler =new MyHandler(ibmComputer); 4 computer=(SellComputer) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), handler); 5 System.out.println(computer.sell());
参考资料:
http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
http://langyu.iteye.com/blog/410071
http://iluoxuan.iteye.com/blog/1629975
http://www.cnblogs.com/mengdd/archive/2013/01/30/2883495.html