软件开发行业有一个观点:任务问题都可以添加一个中间层来解决。代理模式也是这个思想下的产物。
首先看下代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。就是把类委托给另外一个类,用这个类来控制对原来那个类的访问,例如对权限的控制。来看下类图。
代理分为静态代理和动态代理。接下来我们先看下静态代理。
静态代理
1 //接口 2 public interface Human { 3 public void eat(); 4 5 public void breath(); 6 } 7 8 //原来的对象 9 public class Baby implements Human { 10 public void eat(){ 11 System.out.println("在吃奶"); 12 } 13 14 public void breath(){ 15 System.out.println("一刻不停的呼吸!"); 16 } 17 } 18 19 //代理类 20 public class Mom implements Human{ 21 private Human human; 22 public Mom(){ 23 this.human = new Baby(); 24 } 25 26 public void eat(){ 27 System.out.println("喂婴儿吃奶!"); 28 human.eat(); 29 } 30 31 public void breath(){ 32 human.breath(); 33 } 34 } 35 36 public class Client { 37 public static void main(String[] args) { 38 Human hm = new Mom(); 39 hm.eat(); 40 hm.breath(); 41 } 42 } 43 44 ------------------------------------------------------------------------- 45 喂婴儿吃奶! 46 喜欢吃奶 47 一刻不停的呼吸!
动态代理
动态代理的例子是利用了上面的例子中的 human 接口和 Baby 类。
//动态代理 public class ProxyMom implements InvocationHandler { private Human human = null; public Human getProxyInterface(Human human1){ this.human = human1; Human hm = (Human)Proxy.newProxyInstance(human.getClass().getClassLoader(), human.getClass().getInterfaces(), this); return hm; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object methodObj = null; System.out.println("喂婴儿吃奶!"); methodObj = method.invoke(human, args); return methodObj; } } public class Client { public static void main(String[] args) { ProxyMom pm = new ProxyMom(); Human baby= pm.getProxyInterface(new Baby()); baby.eat(); baby.breath(); } } ------------------------------------------------------------------------- 喂婴儿吃奶! 在吃奶 喂婴儿吃奶! 一刻不停的呼吸!
1、java 里面动态代理需要实现 InvocationHandler 接口。
2、然后重写 invoke 方法。参数第一个是:代理类对象。第二个是:需要代理的方法、第三个是方法的参数。另外 invoke 是自动被调样的。不需要使用者显示调用。
通过例子我们看出来了,如果是静态代理的话,代理类和原生类都是一对一的。原生类有多少方法,那么代理类基本也需要有相应的方法来代理,这样代理类总是要跟着原生来来变化。当原生类有很多方法的时候,代理类也需要很多方法,非常的不灵活。而动态代理通过 Proxy、InvocationHandler 和 方法 invoke 就结局了这个问题。因为 invoke 能对所以的方法进行统一处理。方便灵活。
java 的动态代理只能代理接口,而如果想要代理类,需要用到 cglib 类库。
代理的典型用例
1、远程代理。2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
通过典型用法也看出来代理模式的本质就是控制对类的访问
代理模式和装饰模式的区别
当然他们在实现上是极为相似的。但是代理模式强调的是对类的访问控制,而装饰模式主要是为了给类动态的增强功能。