代理模式(静态代理)的通俗理解

来源:互联网 发布:sql关联表查询 编辑:程序博客网 时间:2024/05/17 22:40

代理模式分为两种:静态代理和动态代理。

首先不谈模式,举一个例子:

       有一队很美丽的妹子,她们都是训练有素的迎宾小姐。平时忙于训练再加上人脉与广告投入不多,生意并不好。于是她们的老大提议去找一个礼仪公司合作,请他们把迎宾的活儿包给她们来做。恰好在某个公司有个接待外宾的活动,该活动交给一个这个知名的礼仪公司负责,礼仪公司就通知了迎宾小姐。在外宾下车时就要乐队奏乐,走到公司门口时,迎宾小姐需要致以问候。现在来模拟一下这个情景。

[java] view plain copy
  1. //相当于迎宾小姐(委托类)  
  2. public class HelloWorld {  
  3.     public void sayhello(){  
  4.         System.out.println("Hello!");  
  5.     }  
  6. }  
  7.   
  8. //相当于这个礼仪公司(代理类)  
  9. public class StaticProxy{  
  10.     //持有了迎宾小姐的资源  
  11.     private HelloWorld helloWorld = new HelloWorld();  
  12.     //迎宾活动  
  13.     public void sayhello() {  
  14.         //自己的乐队奏乐  
  15.         System.out.println("do  something....");  
  16.         //迎宾小姐欢迎  
  17.         helloWorld.sayhello();  
  18.     }  
  19.       
  20.     public static void main(String[] args) {  
  21.         StaticProxy staticProxy = new StaticProxy();  
  22.         staticProxy.sayhello();  
  23.     }  
  24. }  

       可是事情进展的并不顺利,突然听说这些个外宾都会中文,而且其中的重量级人物很喜欢中国传统文化。于是该公司要求礼仪公司立即换掉迎宾小姐,请一队着汉服而且普通话好的来。幸好该队迎宾小姐都是狠角色,各种场面都能应付。

于是我们做如下修改:

[java] view plain copy
  1. //相当于迎宾小姐新阵容  
  2. public class HelloWorld2 {  
  3.     public void sayhello(){  
  4.         System.out.println("您好!");  
  5.     }  
  6. }  
  7. //相当于这个礼仪公司  
  8. public class StaticProxy{  
  9.     //持有了第二队迎宾小姐的资源  
  10.     private HelloWorld2 helloWorld2 = new HelloWorld2();  
  11.     //迎宾活动  
  12.     public void sayhello() {  
  13.         //自己的乐队奏乐  
  14.         System.out.println("do  something....");  
  15.         //迎宾小姐欢迎  
  16.         helloWorld2.sayhello();  
  17.     }  
  18.       
  19.     public static void main(String[] args) {  
  20.         StaticProxy staticProxy = new StaticProxy();  
  21.         staticProxy.sayhello();  
  22.     }  
  23. }  

迎宾队伍的老大又想,这样太麻烦了,每次换来换去的折腾不起,倒不如我们再召些人马,加强多元化的训练,使自己的团队能应付各种场面,然后根据需求迅速做出响应。

[java] view plain copy
  1. //专业迎宾团队  
  2. public interface IHelloWorld {  
  3.     //规定了做什么  
  4.     public void sayhello();  
  5. }  
  6. //第一小队  
  7. public class HelloWorldImpl implements IHelloWorld{  
  8.     //照着规章去做     说英语  
  9.     public void sayhello(){  
  10.         System.out.println("Hello!");  
  11.     }  
  12. }  
  13.   
  14. //第二小队  
  15. public class HelloWorldImpl2 implements IHelloWorld {  
  16.     //同样是致欢迎   用标准普通话  
  17.     @Override  
  18.     public void sayhello() {  
  19.         System.out.println("您好 !");  
  20.     }  
  21. }  

修改代理类:

[java] view plain copy
  1. //相当于这个礼仪公司  
  2. public class StaticProxy{  
  3.     //持有了迎宾团队的资源  
  4.     private IHelloWorld hello ;  
  5.     
  6.     public StaticProxy() {  
  7. //招呼迎宾团队准备上场,具体派哪对视情况而定  
  8.         hello = new HelloWorldImpl();  
  9.         //hello = new HelloWorldImpl2();  
  10.     }  
  11.   
  12.     //迎宾活动  
  13.     public void sayhello() {  
  14.         //自己的乐队奏乐  
  15.         System.out.println("do  something....");  
  16.         //迎宾小姐欢迎  
  17.         hello.sayhello();  
  18.     }  
  19.       
  20.     public static void main(String[] args) {  
  21.         //该公司并不知道有迎宾团队的存在   它只和代理(礼仪公司)接触  
  22.         StaticProxy staticProxy = new StaticProxy();  
  23.         staticProxy.sayhello();  
  24.     }  
  25.       
  26. }  

    修改后的代码可以说是一个静态代理了,设计模式提倡针对接口编程,而不是针对实现编程,这样可以灵活多变。最开始的代码可以说是一种代理,但不是一种模式,模式讲究的是良好的设计,如果进一步强调通用性和可扩展性,那就不得不提到JDKcglib的动态代理。


从上面来总结一下静态代理:

    有些类由于自己功能有限,需要其他的类做一些工作来辅助完成某些功能,虽然这些辅助工作是必须的,但是委托类却不需要自己去做,一是他没有资源,二是它应该注重自己擅长的事情。这样一些代理类应运而生,它专门做一些事前和善后的处理,让委托类专注于自己的事情。在生活中有很多这样的例子,就像上面的迎宾团队,它的团队训练有素,能力很强,但是它却没有能力去接一些大活儿,这样他可以去找礼仪公司,两者签订合作协议,让礼仪公司出去接活儿,迎宾部分到时候包给该团队去做,这样各得其所。还有就是常常在幕后为明星忙碌的经纪人,他们就是活生生的代理。

    回到我们程序员的世界,看看那些有名的框架,像struts2中的action调用,hibernate的懒加载,springAOP,无不用到了代理模式,虽然不再是简单的静态代理,但是思想大抵如此。我们使用这些框架时,只需要专注自己的业务逻辑部分,其他重复机械的但不得不做的工作交给了这些幕后英雄。


我的总结:接口由不同的功能类实现,然后在所谓的动态代理实现类中,有这个接口的对象。需要哪个功能就new 哪个功能类。

interface A{

public void a_method();

 }

class B implements A{

public void a_method(){

sysout("b的实现");
}

}

class C implements A{

public void a_method(){

sysout("c的实现");
}

}

class Static_proxy implements A{

private A a=new B();

public void a_method(){

sysout("111111111111111");

a.a_method();

sysout("22222222222222");

}


}

在main(客户端)中,new 一个static_proxy类,直接调用方法。

main(){

Static_proxy s_proxy=new Static_proxy();

s_proxy.a_method();

}

但是这样 一旦需要改变调用的对象(比如原来用的b现在用的c)就不得不

在static_proxy中改,private a=new b;这句。这样显得很愚蠢。

因此重新设计static_proxy类并且为其设置一个有参构造方法,在该构造方法中将需要调用的对象确定:

public class Static_proxy implements A{

private A a;

public static_proxy(A a){

this.a=a;

}

public void a_method(){

sysout("111111111111111");//加一些别的东西

a.a_method();

sysout("22222222222222");

}

}

客户端:main(){

Static_proxy s_proxy=new Static_proxy(new B());

s_proxy.a_method();

}

这样明显优雅很多。