本文最后更新于:3 years ago
                
              
            
            
                在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于  结构型模式    在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。 
如果想了解代理模式的具体的介绍,菜鸟教程介绍得比较详细↓菜鸟教程-代理模式 
结构图 
优缺点 优点: 
1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
使用场景 按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
实现代码 我这里就介绍一下静态代理模式,动态代理真的难度很大。我可能也说的不是很清楚。代理是最难的的一种设计模式, 然后动态代理就是难上加难。这里我推荐一个也是我最近无意中看到的写的很好的一篇文章,下面第一个评论很好地解释了动态代理,难以理解动态代理的人可以康康
动态代理 
提出要求,要求建立一个Main方法,实现Movable接口中的move()方法,接着在move()方法中输出Runing,睡眠5s以内,然后我想记录睡眠的时间。
代码不难,贴出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  class  Main  implements  Movable  {     @Override      public  void  move ()   {         long  start = System.currentTimeMillis();         System.out.println("Moving Moving Moving ..." );         try  {             Thread.sleep(new  Random().nextInt(5000 ));         } catch  (InterruptedException e) {             e.printStackTrace();         }         long  end = System.currentTimeMillis();         System.out.println(end - start);     }     public  static  void  main (String[] args)   {         new  Main().move();     } }interface  Movable  {     void  move ()  ; }
 
代码不难,接着,甲方继续提出要求,记录时间时,不能够修改方法的源码。
首先想到继承,言出码随:
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 interface  Movable  {     void  move ()  ; }public  class  Main  implements  Movable  {     @Override      public  void  move ()   {         System.out.println("Moving Moving Moving ..." );         try  {             Thread.sleep(new  Random().nextInt(5000 ));         } catch  (InterruptedException e) {             e.printStackTrace();         }     }     public  static  void  main (String[] args)   {         new  Main2().move();     } }class  Main2  extends  Main  {     @Override      public  void  move ()   {         long  start = System.currentTimeMillis();         super .move();         long  end = System.currentTimeMillis();         System.out.println(end - start);     } }
 
但是!有一件事情,我想提醒你,设计模式中是需要慎用继承的,因为耦合度太大了。 于是甲方爸爸就不乐意了,不允许你用继承。难受了,那怎么办啊?
这个时候,就需要用到代理的思想,创建一个代理类,实现Movable接口,这个代理中move()方法记录甲方爸爸想记录的东西, 然后这个类中,定义一个Main类型的变量,创建一个有参构造,每次当你创建这个代理类的时候,需要往里面传入一个Main类型的值。 也就是说只要将甲方爸爸的要求写入这个MainProxy类中就可以了。
先给出代码:
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 interface  Movable  {     void  move ()  ; }public  class  Main  implements  Movable  {     @Override      public  void  move ()   {         System.out.println("Moving Moving Moving ..." );         try  {             Thread.sleep(new  Random().nextInt(5000 ));         } catch  (InterruptedException e) {             e.printStackTrace();         }     }     public  static  void  main (String[] args)   {         new  MainProxy(new  Main()).move();     } }class  MainProxy  implements  Movable  {     Main _main;     public  MainProxy (Main _main)   {         this ._main = _main;     }     @Override      public  void  move ()   {         long  start = System.currentTimeMillis();         _main.move();         long  end = System.currentTimeMillis();         System.out.println(end - start);     } }
 
move()方法只记录了我想记录的东西,剩下的都交给_main去实现(这就是聚合),相当于MainProxy就是Main的一个代理 但是代理完了,都是同一类型。 举个栗子,代理商代理苹果,最后不可能是厂家卖的是苹果,到了代理商这里卖的是三星。所以他们实现的接口一定是一样的
完成了甲方爸爸的需求,但是甲方爸爸想了想,觉得应该还有日志记录,访客日志…
无奈,但你也只能满足甲方爸爸一次次提出的无礼的要求:
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 55 56 57 interface  Movable  {     void  move ()  ; }public  class  Main  implements  Movable  {     @Override      public  void  move ()   {         System.out.println("Begin Begin Begin ..." );         try  {             Thread.sleep(new  Random().nextInt(5000 ));         } catch  (InterruptedException e) {             e.printStackTrace();         }     }     public  static  void  main (String[] args)   {         new  MainTimeProxy(new  Main()).move();     } }class  MainTimeProxy  implements  Movable  {     Main _main;     public  MainTimeProxy (Main _main)   {         this ._main = _main;     }     @Override      public  void  move ()   {         long  start = System.currentTimeMillis();         _main.move();         long  end = System.currentTimeMillis();         System.out.println(end - start);     } }class  MainLogProxy  implements  Movable  {     Main _main;     public  MainLogProxy (Main _main)   {         this ._main = _main;     }     @Override      public  void  move ()   {         System.out.println("start ..." );         _main.move();         System.out.println("stop ..." );     } }
 
这里我们只是多加了一个MainLogProxy类,采用了聚合的方法,这样我们可以实现多种代理方式。 但是这个时候,甲方爸爸又提出了新的要求,我需要满足不同的代理顺序, 比如,我有的地方想实现先时间后日志,有的地方想实现先日志后时间。
这时就继承来讲,如果组合使用这些代理中的方法时,先时间后日志,或者先日志后时间 就需要设置不同的继承顺序,那么这个Main的体系就非常复杂了。
而相比继承而言,聚合就比较好解决这个复杂的问题 但如何通过聚合实现这个功能呢?
分析一下,我们要实现的细节,需要在MainTimeProxy中套着MainLogProxy,MainLogProxy中套着Main 而就目前代码而言,我们是不能够实现代理的组合 再看一下代码,问题在于,Main每个代理类中,都代理的是Main方法,MainTimeProxy不能聚合MainLogProxy的,这样是实现不了我们的需求的
把代理中的Main类改为Movable?😂,对的,就是这样:
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 interface  Movable  {     void  move ()  ; }public  class  Main  implements  Movable  {     @Override      public  void  move ()   {         System.out.println("Begin Begin Begin ..." );         try  {             Thread.sleep(new  Random().nextInt(5000 ));         } catch  (InterruptedException e) {             e.printStackTrace();         }     }     public  static  void  main (String[] args)   {                  new  MainTimeProxy(                 new  MainLogProxy(                         new  Main()                 )         ).move();                  new  MainLogProxy(                 new  MainTimeProxy(                         new  Main()                 )         ).move();     } }class  MainTimeProxy  implements  Movable  {     Movable m;     public  MainTimeProxy (Movable m)   {         this .m = m;     }     @Override      public  void  move ()   {         long  start = System.currentTimeMillis();         m.move();         long  end = System.currentTimeMillis();         System.out.println(end - start);     } }class  MainLogProxy  implements  Movable  {     Movable m;     public  MainLogProxy (Movable m)   {         this .m = m;     }     @Override      public  void  move ()   {         System.out.println("start ..." );         m.move();         System.out.println("stop ..." );     } }
 
这个时候再拿出Decorator的结构图
是不是很像,其实学到后来,会发现很多模式都是互通的,这个最后这个系列写完时,总结一下
  就这样,你完成成功了甲方爸爸的所有需求,甲方爸爸很满意。学会了静态代理模式,于是你又愉快的度过了一天。