1.代理模式
作用:为其他对象提供一种代理以控制对这个对象的访问。当你需要用到某一个对象时,你并不是直接去创建他并使用。而是去通过创建另外一个类,另外一个则类对你的目标对象的调用,这个类就叫代理类。目标类则被称为被代理类。
案例:静态代理
interface Music{ void sing(); //唱歌 } class ProxyJay implements Music{ //代理类 private Music music; public ProxyJay(Music music) { this.music = music; } @Override public void sing() { System.out.println("布置场地"); //代理类做的事情 music.sing(); System.out.println("清理场地"); //代理类做的事情 } }
class Jay implements Music{ //目标类(被代理类) @Override public void sing() { System.out.println("为你弹奏肖邦的夜曲……"); } }
//测试类 public class ProxyTest { public static void main(String[] args) { Jay jay=new Jay(); //创建被代理对象 ProxyJay proxyJay=new ProxyJay(jay); //代理对象 proxyJay.sing(); }
运行结果如下:
解释:ProxyJay为代理类,jay为被代理类。按照面向对象的思想,jay是明星,ProxyJay是助理。
当你想要让歌手唱歌时,你可以通过歌手助理来告诉歌手。并且歌手助理会做一些额为的行为来辅助歌手的表演。这些额外的行为不需要歌手来完成。他们所实现的接口相当于表演的流程,代理类和被代理类只需要按照这个流程来实现就可以了。当然其中的代理类可以无需实现接口,其他方式也能代理。但是为了面向对象的思想和规范最好是实现。
静态代理优点:可以对目标对象进行功能增强。
静态代理缺点:一个接口对应一个代理类,如果接口功能发生变化,则代理类也会变化,代码不灵活。如果有n个代理类,相应的也会有n个接口,代码臃肿。违反开闭原则,一次只能代理一个对象
2.动态代理案例
interface Music{ void sing(); } class Jay implements Music{ @Override public void sing() { System.out.println("为你弹奏肖邦的夜曲……"); } } class ProxyJay{ //工厂 private Music music; public ProxyJay(Music music) { this.music = music; } public Object getMusicSing(){ //返回动态代理对象 return Proxy.newProxyInstance(music.getClass().getClassLoader(), music.getClass().getInterfaces(), (proxy, method, objs) -> { //lambda System.out.println("预定场地……"); Object obj= method.invoke(music,objs); System.out.println("清理场地……"); return obj; }); } }
//测试类 public class ProxyTest { public static void main(String[] args) { Jay jay=new Jay(); ProxyJay proxyJay=new ProxyJay(jay); //通过目标对象获取代理对象 Music music=(Music)proxyJay.getMusicSing(); music.sing(); System.out.println(music.getClass()); } }
运行结果如下:
相比与静态代理,动态代理对象不需要实现业务接口。动态代理对象在程序运行前是不存在,而是在程序运行时动态的在内存中构建。而静态代理在编译时就已经确定了代理对象。
jdk动态代理优点:当接口里面的业务功能发生改变时,返回代理对象的方法无需做任何修改。
缺点:还是依赖于接口实现。