设计模式-代理模式
来源:互联网 发布:本子知乎 编辑:程序博客网 时间:2024/05/16 06:43
代理模式有三个主体,代理,委托代理,具体实例。
它最大的作用就是做到了代理和具体实例的解耦,让代理与具体实例之间没有直接关系。
举个栗子:
最近刚好ipx出来,你高高兴兴的买了回来,刚买好回到家没想到一不小心就掉地上,碎屏了,那当然不开心了,找到专卖店去必须让他们维修。因为你知道专卖店是可以搞定这个事情的,具体是给你换一个呢还是修一下呢,你不知道也不用清楚。第二天来拿果然是好了,美滋滋的回家。
站在专卖店角度来看这件事情,有个倒霉顾客,刚买了ipx第一天就坏了,来要求保修,于是,我们接受了顾客的要求。然后把这个手机交给有合作关系的第三方专业维修机构。
维修好之后,记录该顾客的维修记录。
站在专业维修机构来说,ipx发售第一天就有个倒霉蛋买了ipx就坏了,那么,我们就维修手机。好了之后就给专卖店送过去。
上面的例子中,顾客就是代理人,专卖店就是手里委托代理的中间人,而维修机构就是具体的实例(修手机这件事情)。、
代理模式是面向接口的,对于上面的例子,三者共同关注的是修手机这件事情,于是修手机很自然的就可以被抽象出来。
代码结构结构就是下面这样的。
public interface Service { //修手机这件事情 void service(Phone phone);}
public class Phone { //表示手机状态 private boolean status = true; public boolean isStatus() { return status; } public void setStatus(boolean status) { this.status = status; }}
/** * 专卖店 * * Created by Max on 2017/9/25. */public class AppleStore implements Service{ //记录真正维修手机的维修机构。 Service service; public AppleStore(Service service) { this.service = service; } //专卖店的service可以看做是接受了客户的维修委托。 @Override public void service(Phone phone) { System.out.println("======把手机送到维修机构中..."); service.service(phone); System.out.println("======手机维修好了,记录客户的维修记录..."); }}
/** * 专业维修机构 * * Created by Max on 2017/9/25. */public class PhoneService implements Service { @Override public void service(Phone phone) { System.out.println("维修机构拿到了手机..."); //维修手机 phone.setStatus(true); System.out.println("手机修好了..."); }}
Phone phone = new Phone(); //手机坏了。 phone.setStatus(false); AppleStore appleStore = new AppleStore(new PhoneService()); //将手机送到专卖店中去。 appleStore.service(phone); System.out.println("客户拿到的手机.."+phone.isStatus());
输出:
======把手机送到维修机构中...
维修机构拿到了手机...
手机修好了...
======手机维修好了,记录客户的维修记录...
客户拿到的手机..true
客户并不知道维修机构的存在(或者说明面上它找的是专卖店),而维修机构也不知道手机的主人是谁,一切的关键就在于受理委托代理的专卖店。是专卖店在中间起到了桥接联系的作用。
这就是代理模式,而且是代理模式中的静态代理模式。
虽然解耦是代理静态代理的优点,但是缺点也是非常明显的,那就是如果这时候顾客想要把手机壳换成蓝色的,那么势必,service服务必然是要增加换手机壳的方法,专卖店和维修机构必然也是对于换壳这件事情做出反应。那么代码的维护以及复杂度就会增加。
而动态代理可以解决这件事情。
我们看上面这张图,可以分析一下,修手机这件事情只有具体实例永远知道如何修手机,他是必要条件。
而中间的代理,只是接受委托,代理了修手机这件事情,换一个说法,在北京的苹果专卖店可以接受修手机的委托,那么上海的苹果专卖店为什么不可以呢?
因为并非是必要的,也就是说他是可以被替换的。
而专卖店难道就可以接受修手机的方法,肯定是可以接受很多委托代理的(类比各种售后。。)
这么一来的中间的受理的代理者就不再是死的了。
看过银魂的都知道,阿银他们的开的是万事屋,也就是接受任何委托,那么我很好奇啊,如果我让他们接受修手机这件事情他们接不接受啊。
答案当然是可以的了,因为代理任何事情,这就是所以的动态。
java中,这种动态创建代理底层是由反射来做的。
因此,动态代理的两个核心类,都在
java.lang.reflect
反射包下。
InvocationHandler
该接口只有一个invoke,当代理对外的一切方法(专卖店对外公布修手机方法)被调用时,注意,我说的是一切方法被调用!!代理内部(专卖店)就会调用invoke方法,而我们则调用具体的实例(维修机构)来处理具体的业务逻辑(修手机)。
因此我们的代码是这样的。
public class DynamicProxy implements InvocationHandler { //真正的业务逻辑实现类 private Object object; public DynamicProxy(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("我是动态代理..."); result = method.invoke(object,args); System.out.println("动态代理已完成..."); return result; }}
invocationHandler接口可以简单的看成替换了上面例子的Service接口,所有对外公布的方法(接口中的方法),都会转发到invoke这里。
来看看invoke方法参数的三个参数:
1.代理实例,可以理解为对外公布的规范。
2.代理实例有那么多方法,到底调用在转到处理这边时将会具体化成java中的反射的Method对象,method.invoke可以直接执行方法,参数为具体要操作的对象。(也就是Object)。
3.调用方法的参数。
Proxy
类。DynamicProxy并非是动态代理,它只是动态代理被调用的后续处理。
Phone phone = new Phone(); //手机坏了。 phone.setStatus(false); DynamicProxy dynamicProxy = new DynamicProxy(new PhoneService()); //创建动态代理 Service service = (Service)Proxy.newProxyInstance( DynamicProxy.class.getClassLoader(), new Class[]{ Service.class }, dynamicProxy ); service.service(phone);
上面
Proxy.newProxyInstance
才是创建了一个真正的动态代理。
该方法有三个参数,分别是:
1.动态代理类加载器
2.需要实现的接口方法列表。
3.动态代理方法被调用的后续处理程序。
方法返回一个动态代理类,该类可以调用所有参数二中的方法,调用任意一个方法后都会转发给参数三的实例。
简单理解就是你去万事屋说 我要修手机,那么万事屋也是对你说 我要修手机
ni.我要修手机(),
wanshiwu.我要修手机.
上面的测试代码输出:
我是动态代理...
维修机构拿到了手机...
手机修好了...
动态代理已完成...
不好理解的看图说话。
图中不管是A方法还是B方法在invoke都是method。
看图也能看出,第一张图和第二张图最大的不同就是中间的代理整个都换掉了,并且动态代理徐只要实现java提供给我们的类,不需要在去实现每个集体的业务接口。
又大大的把程序的工作细化以及分割。
最后看下代理的小例子代码:
public class DynamicProxy implements InvocationHandler { //真正的业务逻辑实现类 private Object object; public DynamicProxy(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("我是动态代理..."); result = method.invoke(object,args); System.out.println("动态代理已完成..."); return result; }}
public class UserImpl implements User { @Override public void study() { System.out.println("我是 "+this.getClass().getInterfaces()[0].getName()+" 具体的实现类..........."); System.out.println("study.............."); } @Override public int study(String str) { int a = 2; System.out.println("今天学习 " +str); return a; }}
public interface Worker { void work();}
public class WorkerImpl implements Worker { @Override public void work() { System.out.println("我是 "+this.getClass().getInterfaces()[0].getName()+" 具体的业务实现逻辑..."); System.out.println("worker..."); }}
//动态代理模式 DynamicProxy userDynamicProxy = new DynamicProxy(new UserImpl()); User user = (User)Proxy.newProxyInstance( DynamicProxy.class.getClassLoader(), new Class[]{User.class}, userDynamicProxy ); user.study(); String string = "语文"; int a = user.study(string); System.out.println("今天学习语文学习了 "+a+" 个小时"); System.out.println("======================我是分割线=========================="); DynamicProxy workerDynamicProxy = new DynamicProxy(new WorkerImpl()); Worker worker = (Worker)Proxy.newProxyInstance( DynamicProxy.class.getClassLoader(), new Class[]{Worker.class}, workerDynamicProxy ); worker.work();
输出:
我是动态代理...
我是 User 具体的实现类...........
study..............
动态代理已完成...
我是动态代理...
今天学习 语文
动态代理已完成...
今天学习语文学习了 2 个小时
======================我是分割线==========================
我是动态代理...
我是 Worker 具体的业务实现逻辑...
worker...
动态代理已完成...
参考
https://www.daidingkang.cc/2017/07/18/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/
- 设计模式--【代理模式】
- 设计模式:代理模式
- 设计模式--代理模式
- 设计模式---代理模式
- 设计模式-代理模式
- 设计模式---代理模式
- 设计模式 代理模式
- 设计模式-【代理模式】
- 设计模式-代理模式
- 设计模式----代理模式
- 设计模式-代理模式
- 设计模式---代理模式
- 设计模式--代理模式
- 设计模式-代理模式
- 设计模式- 代理模式
- 设计模式---代理模式
- 设计模式 - 代理模式
- 【设计模式】代理模式
- SpringSecurity基于方法保护
- Java命令模式
- html
- HDU
- java集合图谱
- 设计模式-代理模式
- POJ 2566 Bound Found(尺取)
- nginx安装,nginx-lua模块安装(centos7.3)
- 01-复杂度2 Maximum Subsequence Sum(25 分)
- Jboss实现jsp热部署
- The Heaviest Non-decreasing Subsequence Problem ACM-ICPC南宁wa
- 用js实现地图窗体自适应不同的浏览器高度
- SSL证书生成,签名,验证
- CART,回归树,GBDT,XGBoost,LightGBM一路理解过来