代理模式说白了就是中介,A要完成C,并不是直接去完成而是委托中介B去完成,B就是连接A与C的代理,B可以完全替代A去做,有时只需要提供满足C所需要的东西就行。
代理模式分为静态代理(手动实现这些行为的替换) + 动态代理(实现InvocationHandler接口交给虚拟机实现行为的替换)
静态代理
我是一个客户想买一辆车开开,我可以提供买车所有的证件以及买车的行为(具备这些我当然自己就可以去买车了,但是我闲的蛋疼啊,自己去做这些事,毕竟日理万机的工作)
首先呢,我提取了我和中介的共同行为:那就是都可以买车,只是他没有我的相关证件
package com.zndroid.dm.ProxyModel.StaticProxy;
/**
* Created by luzhenyu on 2017/7/27.
*/
public interface IBuyCar {
void buyCar();
}
package com.zndroid.dm.ProxyModel.StaticProxy;
/**
* Created by luzhenyu on 2017/7/27.
*/
public class Client implements IBuyCar {
private int money;
private String certificate;
private String car;
public String getCar() {
return car;
}
public void setCar(String car) {
this.car = car;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getCertificate() {
return certificate;
}
public void setCertificate(String certificate) {
this.certificate = certificate;
}
@Override
public void buyCar() {
System.out.println("客户 - 签合同");
}
}
去4儿子店,找到一个中介,他客气滴招待了我,建立了我和他的联系(通过这个联系他能够拿到我的相关信息),他本身也具备买车的行为
package com.zndroid.dm.ProxyModel.StaticProxy;
/**
* Created by luzhenyu on 2017/7/27.
* 相当于中介
* 通常建议使用的是聚合式代理而非继承式代理
* 聚合实现方式中代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活;
* 比如,在管理员操作的同时需要进行权限的处理,操作内容的日志记录,操作后数据的变化三个功能。三个功能的排列组合有6种,
* 也就是说使用继承要编写6个继承了Admin的代理类,而使用聚合,仅需要针对权限的处理、日志记录和数据变化三个功能编写代理类,
* 在业务逻辑中根据具体需求改变代码顺序即可。
*/
public class Proxy implements IBuyCar {
private Client client;//包含客户的引用,这样中介就能给我要相关的证件资料了
public Proxy(Client client) {
this.client = client;
}
@Override
public void buyCar() {
checkMoney$Certificate();
client.buyCar();//具体实体(客户)动作(也就是最终需要客户签合同操作,代理只起到中介作用,而且客户关心的只是买车,证件检查等操作客户无需关心,交给中介做)
shangPai();
client.setCar(jiaoFu());
}
private void checkMoney$Certificate() {
System.out.println("代理 - 资料核实:" + client.getCertificate() + " and " + client.getMoney());//代理做的东西
}
private void shangPai() {
System.out.println("代理 - 上牌");//代理做的东西
}
private String jiaoFu() {
System.out.println("代理 - 交付车辆");//代理做的东西
return "new car";
}
}
具体使用:
Client mClient = new Client();
mClient.setMoney(100);
mClient.setCertificate("ID card");
Proxy proxy = new Proxy(mClient);
proxy.buyCar();
log("客户获得了:" + mClient.getCar());
log("----------------我是分割线-----------------");
动态代理
基本和静态代理一样,只是要实现InvocationHandler接口,并告诉虚拟机怎么去处理手动插入的过程package com.zndroid.dm.ProxyModel.DynamicProxy;
/**
* Created by luzhenyu on 2017/7/27.
*/
public interface IBuyCar {
void buyCar();
}
package com.zndroid.dm.ProxyModel.DynamicProxy;
/**
* Created by luzhenyu on 2017/7/27.
*/
public class Client implements IBuyCar {
private int money;
private String certificate;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getCertificate() {
return certificate;
}
public void setCertificate(String certificate) {
this.certificate = certificate;
}
@Override
public void buyCar() {
System.out.println("客户 - 签合同");
}
}
package com.zndroid.dm.ProxyModel.DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static java.lang.System.out;
/**
* Created by luzhenyu on 2017/7/27.
* 一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。
* 但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。
* 也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点.
*
* 动态代理是不需要手写代理类的,但是需要实现InvocationHandler接口,在运行时由虚拟机创建代理,
* 实际内部原理 参见<a>http://blog.csdn.net/goskalrie/article/details/52458773<a/>
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object object) {
this.target = object;
}
/**
*@param proxy 被代理的对象
*@param method 被代理对象的方法
*@param args 方法的参数
*@return Object 方法返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("buyCar")) {
checkMoney$Certificate();
}
method.invoke(target, args);
if (method.getName().equals("buyCar")) {
shangPai();
}
return null;
}
private void checkMoney$Certificate() {
String s = "", s1 = "";
try {
Method m = target.getClass().getMethod("getMoney", null);
s = String.valueOf(m.invoke(target, null));
Method m1 = target.getClass().getMethod("getCertificate", null);
s1 = (String)m1.invoke(target, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("代理 - 资料核实:" + s + " " + s1);//代理做的东西
}
private void shangPai() {
System.out.println("代理 - 上牌");//代理做的东西
}
public String jiaoFu() {
System.out.println("代理 - 交付车辆");//代理做的东西
return "new car";
}
public Object getProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
具体使用:
MyInvocationHandler invocationHandler = new MyInvocationHandler(client);
((IBuyCar) (invocationHandler.getProxy())).buyCar();
log("客户获得了:" + invocationHandler.jiaoFu());
log("----------------我是分割线-----------------");
【欢迎上码】
【微信公众号搜索 h2o2s2】