津津乐道设计模式 - 代理模式详解
1、什么是代理模式
现实生活中代理模式随处可见,比如:房屋中介、婚介、快递等等,举个很简单的例子,商家卖货给买家,商家不一定需要直接送货给买家,而是通过快递公司代送,再比如我们买火车票,我们不一定需要到火车站售票处,我们也可以找12306或者代售点去购买。
简单来说代理模式就是为其它对象提供一种代理,从而控制这个对象的访问,从而实现对象目标的保护和增强。这时候有同学要问了代理怎么保护怎么增强? 现在你需要找一个女朋友,你找到了婚介公司代理帮你找女朋友这个事情,通过婚介女方是不知道你实际的长相、经济情况等着里就是婚介公司保护了你的实际隐私,中介为了促成你们,会在女方面前描述你性格温和,品行端正,这里就是中介对你的增强!怎么样很好理解了吧?
代理模式根据代理的创建时期,代理模式又分为静态代理和动态代理。
2、静态代理
静态代理是指在应用程序初始化时前就已经存在代理类,还是婚介的例子,就是在找女朋友之前,你就已经和婚介建立了委托和代理关系,也就是你已经已经做好了相关工作(要求、缴费),婚介和你已经做好了关联。
我们将上述描述以代码形式来呈现。
//定义一个人的接口,人会又很多行为,吃饭睡觉等这里我们定义找女朋友findGirlFriend
public interface Person {
void findGirlFriend();
}
张先生需要找女朋友
public class MrZhang implements Person {
@Override
public void findGirlFriend() {
System.out.println("张先生的要求白富美");
}
}
婚介媒人帮张先生找女孩
public class Matchmaker {
private MrZhang mrZhang;
public Matchmaker(MrZhang mrZhang){
this.mrZhang = mrZhang;
}
//目标对象的引用
public void findGirl(){
System.out.println("婚介媒人开始物色女孩");
System.out.println("婚介媒人开始对张先生增强:张先生高富帅,值得交往!");
this.mrZhang.findGirlFriend();
System.out.println("双方确立关系,开始没羞没躁的生活");
}
}
看看测试代码
//测试代码
public static void main(String[] args) {
Matchmaker matchmaker = new Matchmaker(new MrZhang());
matchmaker.findGirl();
}
运行结果如下:
上述代码案例,不知道小伙伴发现问题了没有,一开始婚介就已经和张先生建立了关系,public Matchmaker(MrZhang mrZhang),也就是说婚介媒人没办法再帮王先生、李先生找女朋友了。注意这里代理理解:张先生并不是不能自己找女朋友 new MrZhang().findGirlFriend(),只是张先生委托给了Matchmaker。
3、动态代理
上面静态代理的问题大家看到了,已经不能满足我们的设计要求了,现在业务需要扩展,就需要动态代理实现,因为动态代理可以服务多个目标对象。还是找女朋友的例子,我们继续改造一下。
新增老王找女朋友
public class MrWang implements Person {
@Override
public void findGirlFriend() {
System.out.println("王先生的要求是个女人就行");
}
}
创建动态代理
public class DynamicProxy implements InvocationHandler {
//定义代理对象
private Object target;
public Object getInstance(Object target){
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(
//指定生产代理对象的类加载器
clazz.getClassLoader(),
//指定目标对象的实现接口
clazz.getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("婚介媒人已经和委托人建立了关系");
System.out.println("婚介媒人开始物色女孩");
Object object = method.invoke(this.target, args);
System.out.println("如果双方合适同意交往");
return object;
}
}
测试运行
//开始测试 还是张先生 以及新增的老王
public static void main(String[] args) {
Person mrZhang = (Person)new DynamicProxy().getInstance(new MrZhang());
mrZhang.findGirlFriend();
System.out.println();
Person mrWang = (Person)new DynamicProxy().getInstance(new MrWang());
mrWang.findGirlFriend();
}
运行结果如下:
4、结语
静态代理和动态代理主要有以下几点区别:
- 静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,则代理类需要同步增加,违背开闭原则。
- 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
- 若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。
代理模式的优缺点:
优点:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性
缺点:
- 代理模式会造成系统设计中类的数量增加
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
至此本文介绍了代理模式的静态代理和动态代理,并以实际的现实案例作为代码演示,通过本章节希望对大家对代理模式有一个更清晰的理解;
样例代码:https://github.com/lhmyy521125/toher-designmode