设计模式学习_代理模式
问题
最近在做项目时,要封装一个树状对象的对话框,于是上网百度了一个别人做好的东西移植过来。突然发现,如果项目的树状对象要套在他这个控件上面要加多几个属性,那不是我要装上去的对象都要加多几个与它无关的属性?那以后这个对象做其他用途是不是也要加多几个无关属性?想想感觉不对头,就好像你要跑步难道就要给你移植双猪脚?你要去北京难道要给你移植对鸡翅?这样明显不合理嘛,勉强有幸福么?我只需要个代步工具而已。这时牛逼的同事问:“你是不是要用代理模式?”我脑袋上的灯,顿时亮了起来。百度之。。。
意图
通过一个代理(proxy)或者占位符来控制对该对象的访问。
模型图——无
举例
这里讲一个借刀杀怪的故事吧。我们玩游戏时,喜欢带妹纸杀怪升级。至于为何喜欢带妹纸杀怪升级?那是因为游戏玩家都是新时代的活雷锋,以助人为乐。话说有一天,小明头顶着“杀怪大湿”光环身穿着一身极品而且闪耀着非常耀眼光芒的装备站在大街上。不时发出嘹亮的笑声。听说这不是在装B而是为了给城外的妖怪压力。这时,一个身材丰满,但装备破烂的美女跑过来嘀咕了几句。然后他们两就兴高采烈的踏上了杀怪之旅。
杀角色需求分析:杀怪需要杀怪的能力 ,杀怪后可以获得任务物品。小明有杀怪能力,但他不需要任务物品。妹纸没杀怪能力,但需要捡任务物品。于是就有了这样的分工:小明杀怪,妹纸捡任务物品。
首先我们先定义杀怪能力接口,必须实现这个接口才可以杀怪
public interface Killable {
public void KillAction(String str);
}
然后小明实现了这个接口
public class Role implements Killable{
private String name;
public Role(String name) {
// TODO Auto-generated constructor stub
this.name=name;
}
@Override
public void KillAction(String str) {
// TODO Auto-generated method stub
System.out.println(this.name+"使出了降龙十八掌杀死"+str);
}
}
然后妹纸作为了一个没能力杀怪的代理角色,也要实现接口
public class KillProxy implements Killable{
private Killable killable;
public KillProxy(Killable killable) {
// TODO Auto-generated constructor stub
this.killable=killable;
}
@Override
public void KillAction(String str) {
// TODO Auto-generated method stub
sneerMonster(str);
killable.KillAction(str);
makeMoney(str);
}
public void sneerMonster(String name)
{
System.out.println("妹纸跳了段牛逼肚皮舞吸引"+name+"过来");
}
public void makeMoney(String name)
{
System.out.println("妹纸从"+name+"口袋捡起了任务物品");
}
}
开始杀怪了
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Killable killable=new KillProxy(new Role("小明"));
killable.KillAction("巨兽");
}
}
运行结果print:
妹纸跳了段牛逼肚皮舞吸引巨兽过来
小明使出了降龙十八掌杀死巨兽
妹纸从巨兽口袋捡起了任务物品
结果分析
看调用方法,我明显new 出来的是妹纸,小明明显没有和巨兽有接触。巨兽以为是被妹纸杀死的,其实是被妹纸借用小明杀怪方法杀死的。者就是传说中的借刀杀怪了。
任务完成
就这样,小明和妹纸过上了幸福生活。
幕后分析
上面的代理模式是通过实现接口类完成的,而且只能对实现这个接口的对象有用。网上说如果一个接口一个代理类,那是不是造成代理类增多,于是我有百度下——据说百度的码农不是好码农。好吧我承认自己是低手。但我觉得一个人愿意查找问题解决问题就是一个好的开始。
动态代理模式
对于动态代理,我的理解是,做个通用的代理类,可以代理实现任何接口的对象。就是比上面那个更通用。
动态代理实现方法
用java的放射机制生产目标对象的代理类,就是动态实现上面例子的妹纸代理类。任何执行接口方法。你可以在执行接口方法的前后加上自己的一些处理。
/**
* java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力
* @author Administrator
*
*/
public class Xproxy implements InvocationHandler{
private Object object;
public Object bind(Object object)
{
this.object=object;
//取得代理对象
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);
}
/**
* method 目标对象实现的接口 接口方法
* args方法执行所需的参数
* proxy听说是被代理对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Object result=null;
if(args.length>0)
System.out.println("妹纸跳了段牛逼肚皮舞吸引"+args[0]+"过来");
result=method.invoke(this.object, args);
if(args.length>0)
System.out.println("妹纸从"+args[0]+"口袋捡起了几毛钱");
return result;
}
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
/*Killable killable=new KillProxy(new Role("小明"));
killable.KillAction("巨兽");*/
Role role=new Role("小明");
Xproxy xproxy=new Xproxy();
Killable killable=(Killable) xproxy.bind(role);
killable.KillAction("哥布林");
}
}
运行结果:
妹纸跳了段牛逼肚皮舞吸引哥布林过来
小明使出了降龙十八掌杀死哥布林
妹纸从哥布林口袋捡起了几毛钱
代理模式就先告一段落。
备注:上面的故事例子纯属扯淡,有被污染者,自行洗脑。关于何时用这个模式,看自己实际需求,起码先掌握了,脑里有这个概念,可能后面碰到有很适合这个代理模式的需求的,你写起代码来就得心应手了。