体验设计模式之旅(一):代理模式

来源:互联网 发布:软件设计师考纲 编辑:程序博客网 时间:2024/05/20 21:57

注:此乃博主原创文章转载请注明http://blog.csdn.net/weixin_38243254/article/details/78654599


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

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。


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


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


在代理模式中的角色:


  ●  抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。(买票)


  ●  目标对象角色:定义了代理对象所代表的目标对象。(火车站)


  ●  代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。(票务中心)




举例:若是一个人想买爱马仕的限量版包包,但在中国买不到,所以此时只能依靠代理商来买。所以此时几个对象角色为:
    抽象对象角色:卖爱马仕的包(也就是一个卖包的接口,交给下面的爱马仕公司实现)
    目标对象角色(真实角色):爱马仕公司(他有生产爱马仕包包的能力,也就是实现了上面的接口)
    代理对象角色:爱马仕中国代理商(他其实不具备生产爱马仕的能力,但他持有真实角色的引用,它是靠爱马仕公司生产包包)
//抽象角色
public interface saleBag(){
  public void bag();
}
//真实角色
public class Hermes implements saleBag(){
  public void bag(){
     //生产爱马仕的一些操作
     system.out.println("生产出爱马仕");
  }
}
//代理角色(爱马仕中国代理商)
public class hermesProxy implements saleBag(){
  Hermes hermes=new Hermes();//代理商持有爱马仕公司的引用
  public void bag(){
    //代理商做一些先行处理(如联系爱马仕公司)
    。。。。。。。。。。。。。
    //真正的爱马仕公司生产爱马仕包包
    hermes.bag();
    //代理商做一些后续处理(如增加手续费)
    。。。。。。。。。
   } 
}


//买包的客户
public class Client {


    public static void main(String[] args) {
        // 找到代理商买爱马仕的包包
        hermesProxy obj = new hermesProxy ();
        obj.bag();
    }
}


此种代理模式为静态代理(也就是一个代理商只能代理一种平牌),若客户想要买其他品牌的包就必须找另一个代理商,此时就必须新增一个代理类,如果做大量代理就会引起代理类暴增。要解决该情况可用动态代理(以一个代理类代理所有商品),动态代理是通过反射的方式在运行过程中将客户端所需代理的产品动态的引入代理类。


例如:此时顾客想买lv的包
//增加产lv包的真实角色
public class Lv implements saleBag(){
  public void bag(){
     //生产LV的一些操作
     system.out.println("生产出LV");
  }
}
//将爱马仕代理商改为所有包包的总代理(需实现实现InvocationHandler接口  )
class DynamicProxy implements InvocationHandler {  

   // 被代理类的实例  
   Object obj = null;//这里并未指定具体的代理物品,而是交给构造函数传入  
 
    // 将被代理者的实例传进动态代理类的构造函数中  
   public DynamicProxy(Object obj) { //这里的obj是指需代理的产品(如想买LV就传入LV,想买hermes就传入hermes) 
       this.obj = obj;  
    }  

    /**  
    * 覆盖InvocationHandler接口中的invoke()方法  
     *   
    * 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构  
    * 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到  
    * 控制被代理对象的行为,下面的before、after就是我们可以进行特殊  
     * 代码切入的扩展点了。  
     */ 
   public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        /*  
        * before :doSomething();  
       */ 
       Object result = method.invoke(this.obj, args);  
          
       /*  
        * after : doSomething();  
       */ 
      return result;  
    }  





   //客户类 
51.public class Client {  
52.    public static void main(String[] args) {  
53. 
54.        // 被代理类的实例  
55.        Lv lv= new Lv ();  
56. 
57.        // 获得被代理类的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface  
58.        ClassLoader loader = lv.getClass().getClassLoader();  
59. 
60.        // 获得被代理类已实现的所有接口interface,使得动态代理类的实例  
61.        Class<?>[] interfaces = lv.getClass().getInterfaces();  
62. 
63.        // 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序  
64.        InvocationHandler handler = new DynamicProxy(lv);  
65. 
66.        /*  
67.         * loader : 被代理类的类加载器  
68.         * interfaces :被代理类已实现的所有接口,而这些是动态代理类要实现的接口列表  
69.         * handler : 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序  
70.         *   
71.         * return :返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型  
72.         */ 
73.        //获得代理的实例  
74.        AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(  
75.                loader, interfaces, handler);  
76. 
77.        proxy.bag();  
78.        //打印出该代理实例的名称  
79.        System.out.println(proxy.getClass().getName());  
80.    }  
81.}