代理模式有三个主体,代理,委托代理,具体实例。
它最大的作用就是做到了代理和具体实例的解耦,让代理与具体实例之间没有直接关系。
举个栗子:
最近刚好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中,这种动态创建代理底层是由反射来做的。
因此,动态代理的两个核心类,都在
反射包下。
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/