目录
定义
通用类图
普通代理
强制代理
代理扩展
动态代理
参考
回到顶部
定义
为其他对象提供一种代理以控制对这个对象的访问。
代理模式也叫委托模式,日常生活中很常见。帮别人做某某事情时候,自己就是别人的代理;让别人帮自己做什么事情时候,别人就是自己的代理。
通用类图
Subject抽象主题角色
抽象主题类是一个普通的业务类型的定义,规定要做什么事情。可以是一个抽象类也可以是一个接口。
RealSubject具体主题角色
被委托(被代理)的角色,是真正事情处理的执行者。
Proxy代理主题角色
委托类(代理类),负责对真实角色的调用,把所有主题限定的方法委托给具体主题角色,也可以在真实主题角色处理前做一些预处理,或在真实主题角色处理后做一些善后处理(比如Spring的AOP)。
回到顶部
普通代理
小时候在家都是妈妈做饭,做饭需要洗菜,切菜,炒菜……有时候妈妈有事忙没按时回家,姐姐就偷偷代替妈妈给大家做饭。如果将做饭简单理解为洗菜、切菜、炒菜三个步骤,从程序员的角度来记录做饭这件事就很简单了。妈妈和姐姐都需要洗菜、切菜然后再炒菜,所以可以规定炒菜的三个步骤,然后分别实现这三个步骤,所以可以简单表示为:
ICook定义了炒菜必须要经历的流程:
复制代码
public interface ICook {
/**洗菜*/
void washFood();
/**切菜*/
void cutFood();
/**炒菜*/
void stirFood();
}
复制代码
妈妈(对于一家人来说,天天吃妈妈做的饭,妈妈就是一个Cooker)做饭的流程:
复制代码
public class Cooker implements ICook {
@Override
public void washFood() {
System.out.println("妈妈在洗菜……");
}
@Override
public void cutFood() {
System.out.println("妈妈在切菜……");
}
@Override
public void stirFood() {
System.out.println("妈妈在炒菜……");
}
}
复制代码
一个能代理妈妈做饭(实现了ICook接口)的角色
复制代码
public class CookerProxy implements ICook {
private ICook cooker;
public CookerProxy(ICook cooker){
this.cooker = cooker;
}
@Override
public void washFood() {
this.cooker.washFood();
}
@Override
public void cutFood() {
this.cooker.cutFood();
}
@Override
public void stirFood() {
this.cooker.stirFood();
}
}
复制代码
姐姐代替妈妈做饭
复制代码
public void test() {
Cooker cooker = new Cooker();
ICook cook = new CookerProxy(cooker);
cook.washFood();
cook.cutFood();
cook.stirFood();
}
复制代码
姐姐学会了妈妈的手艺,如果不是亲眼看到,还不知道是姐姐做的饭,这就是真实生活中一个简单的代理例子。
回到顶部
强制代理
普通代理是通过代理找到真实的对象,由真实对象去执行动作;但是强制代理却是要通过真实角色查找代理,否则不能访问。也就是不管是通过代理类还是直接new一个真实对象都不能访问,只有通过真实对象委托的代理才能访问。
还是上面的那个例子,后来妈妈上班去了,中午不能回家做饭了,拿普通代理方式来说,只要是一个会做菜的人,就可以趁着妈妈不在冒充妈妈的身份替妈妈做菜,万一做的很难吃,岂不是把妈妈的招牌给毁了吗?
于是,妈妈想到了个办法,必须由她指定谁可以代替她做菜,不是由她亲自指定的人无法替她做菜:
定义了一个getProxy方法,由Cooker来指定自己的代理,并且代理自己做事之前,先验证下身份:
复制代码
public class Cooker implements ICook {
private ICook cook;
@Override
public void washFood() {
if (this.isProxy()) {
System.out.println("妈妈在洗菜……");
} else {
System.out.println("请妈妈指定的人来炒菜……");
}
}
@Override
public void cutFood() {
if (this.isProxy()) {
System.out.println("妈妈在切菜……");
} else {
System.out.println("请妈妈指定的人来炒菜……");
}
}
@Override
public void stirFood() {
if (this.isProxy()) {
System.out.println("妈妈在炒菜……");
} else {
System.out.println("请妈妈指定的人来炒菜……");
}
}
@Override
public ICook getProxy() {
this.cook = new CookerProxy(this);
return this.cook;
}
private Boolean isProxy() {
if (this.cook == null) {
return false;
}
return true;
}
}
复制代码
只有通过Cooker对象获取(getProxy)代理才能做菜。
回到顶部
代理扩展
姐姐做了几顿饭之后也开始不乐意了,凭什么我要占用玩的时间来给大家做饭?妈妈想了一个好主意,姐姐每做一顿饭可以从妈妈那里领到1块钱,于是姐姐又高高兴兴地给大家做饭了。做饭和付钱是两个单独的功能,是不能混在一起的,可以将上面类图稍作修改:
这样,在每次做好饭之后就可以记账应该拿到1元钱
复制代码
public class CookerProxy implements ICook, IPay {
private ICook cooker;
public CookerProxy(ICook cooker){
this.cooker = cooker;
}
@Override
public void washFood() {
this.cooker.washFood();
}
@Override
public void cutFood() {
this.cooker.cutFood();
}
@Override
public void stirFood() {
this.cooker.stirFood();
this.pay();
}
@Override
public void pay() {
System.out.println("做完饭拿到了1元钱");
}
@Override
public ICook getProxy() {
/** 可以指定代理的代理,暂时没有就是自己 */
return this;
}
}
复制代码
代理不仅可以实现主题的接口,还可以实现其他的接口,在目标行为基础之上做个性化处理。
回到顶部
动态代理
后来姐姐长大了,也出门在外了,我们也不能每次都等着吃饭,于是各自都学会了做饭,只要妈妈不在,谁方便了谁就做饭。也就是说,只有饭已经在被做了才知道是谁在做,更灵活了,这就不能提前指定谁来做饭了。对应程序中是:只有在运行时才知道真实类型是谁。
将类图稍作修改,如下所示。
InvocationHandler是java提供的动态代理接口,CookerHandler实现了InvocationHandler接口,这样可以动态指定代理,运行时才知道类型。
复制代码
public class CookerHandler implements InvocationHandler {
Class clazz = null;
Object obj = null;
public CookerHandler(Object _obj) {
this.obj = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
return result;
}
}
复制代码
动态代理客户端使用示例:
复制代码
public void dynamicProxy(){
proxy.dynamicproxy.ICook cook = new proxy.dynamicproxy.Cooker();
ClassLoader classLoader = cook.getClass().getClassLoader();
Class>[] interfaces = cook.getClass().getInterfaces();
CookerHandler handler = new CookerHandler(cook);
proxy.dynamicproxy.ICook proxyInstance = (proxy.dynamicproxy.ICook) Proxy.newProxyInstance(classLoader, interfaces, handler);
proxyInstance.washFood();
proxyInstance.cutFood();
proxyInstance.stirFood();
}
复制代码https://www.cnblogs.com/mr-yang-localhost/p/9746184.html