标签:
随着业务规模的增大,为了方便管理两间工厂,小成和他的合伙人建立了一间公司,把一些不是很重要的生意交给手下业务员代表公司去和其他公司谈,如果业务员超常发挥,还可能为公司谈好一笔任务之外的生意。这样老板小成就可以轻松很多了,小成一有空就想写代码,一想这个不就是代理模式吗,然后就开始写下代码。
在有些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个代理来实现间接引用。就像我们现在的不能直接访问谷歌,要通过代理翻墙才行。
代理模式的定义就是为其他对象提供一种代理以控制对这个对象的访问。在代理模式中,代理者在代替被代理者执行操作时,还可以增加自己的操作。
代理模式中有几个重要的角色:
- 抽象对象父类(Subject):是真实对象类和代理类的共同父类,这样一来在任何使用真实对象类的地方都可以使用代理类。
- 真实对象类(RealSubject):定义了代理类所代表的真实对象类,真正执行操作的对象。
- 代理类(Proxy):代理类里面含有对真实对象类的引用,从而可以操作真实对象,而且代理类可以在将客户端调用真实对象的操作之前或之后,加上自己的一些操作,而不是单纯的将调用传递给真实主题对象,像下面的代码,公司代理额外谈好一单生意就是代理自己的操作。
package scut.designmodel.ProxyPattern;
//公司类
abstract class Company {
//公司名字
public String CompanyName;
//公司谈判
public abstract void Negotiate();
//公司签约
public abstract void Sign();
}
//小成的公司,真正的谈判对象,也就是被代理的对象
class XiaoChengCompany extends Company {
@Override
public void Negotiate() {
System.out.println(CompanyName +"正在与其他公司谈判");
}
@Override
public void Sign() {
System.out.println(CompanyName +"签好了合约");
}
}
//小成公司的代理
class XiaoChengCompanyProxy extends Company {
private XiaoChengCompany mXiaoChengCompany;
//代理建立的构造函数,建立一个公司实例,把公司名信息给它
public XiaoChengCompanyProxy(String CompanyName){
mXiaoChengCompany = new XiaoChengCompany();
mXiaoChengCompany.CompanyName = CompanyName;
}
@Override
public void Negotiate() {
mXiaoChengCompany.Negotiate();
ExtraBusiness();
}
@Override
public void Sign() {
mXiaoChengCompany.Sign();
}
//代理的额外动作
public void ExtraBusiness(){
System.out.println("代理额外谈好了一单生意");
}
}
//使用代理和进行其他公司进行谈判签约的过程
public class ProxyPattern {
public static void main(String[] arg){
XiaoChengCompanyProxy mXiaoChengCompanyProxy = new XiaoChengCompanyProxy("小成的公司");
mXiaoChengCompanyProxy.Negotiate();
mXiaoChengCompanyProxy.Sign();
}
}
运行结果:
小成的公司正在与其他公司谈判
代理额外谈好了一单生意
小成的公司签好了合约
保护代理可以控制对真实对象的使用权限。
小成的公司虽然刚刚成立,但是还是成立了各种部门分管事务。有一些部门很缺人,例如产品部和广告部就需要人手,然后就会委托人事部去招人,人事部就是他们的代理。小成一开始想用静态代理模式来实现这样的代码,但是静态代理对象只服务于一个部门,如果要代理另外一个部门又要重新写,那为什么不写一个可以代理所有部门的代理呢?于是小成就从网上找到了动态代理模式。
动态代理模式解决了静态代理的要手动实现代理的缺点,只需要把代理类实现InvocationHandler接口,就可以通过基于java反射机制的method.invoke方法来自动调用被代理类的方法,不用手动实现。
动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。我们在设计动态代理类(DynamicProxy)时不用显式地让它实现与真实对象类(RealSubject)相同的接口,而是把这种实现推迟到运行时。
可以看下面的代码:
动态代理类:
为了能让PersonnelDepartment类能够在运行时才去实现真实对象类已实现的一系列接口并执行接口中相关的方法操作,需要让DynamicProxy类实现JDK自带的java.lang.reflect.InvocationHandler接口。
package scut.designmodel.DynamicProxyPattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class PersonnelDepartment implements InvocationHandler {
// 代理对象
private Object ProxyObject;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object ProxyObject){
this.ProxyObject =ProxyObject;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(ProxyObject.getClass().getClassLoader(),
ProxyObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被执行
//InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("人事部准备场地");
Object result=null;
switch (method.getName()) {
case "Negotiate":
try {
/*原对象方法调用前代理的动作*/
System.out.println("人事部邀请应聘者面试谈判");
//运用java反射机制调用目标方法
result = method.invoke(ProxyObject, args);
/*原对象方法调用后代理的动作*/
System.out.println("谈判成功,人事部制定合同");
} catch (Exception e) {
e.printStackTrace();
System.out.println("谈判失败");
throw e;
}
break;
case "Sign":
try {
//原对象方法调用前代理的动作
System.out.println("人事部邀请应聘者面试签约");
//运用java反射机制调用目标方法
result = method.invoke(ProxyObject, args);
//原对象方法调用后代理的动作
System.out.println("签约成功,人事部安排新同事上班");
} catch (Exception e) {
e.printStackTrace();
System.out.println("签约失败");
throw e;
}
break;
}
System.out.println("----------------");
return result;
}
}
实际类:
package scut.designmodel.DynamicProxyPattern;
//部门类
interface Department {
//部门谈判
public void Negotiate();
//部门签约
public void Sign();
}
//广告部门,真正的谈判对象,也就是被代理的对象
class AdvertisingDepartment implements Department {
@Override
public void Negotiate() {
System.out.println("广告部正在和应聘者谈判");
}
@Override
public void Sign() {
System.out.println("广告部和应聘者签好了合约");
}
}
//产品部门,真正的谈判对象,也就是被代理的对象
class ProductDepartment implements Department {
@Override
public void Negotiate() {
System.out.println("产品部正在和应聘者谈判");
}
@Override
public void Sign() {
System.out.println("产品部和应聘者签好了合约");
}
}
//人事部动态代理两个部门的招聘工作流程
public class DynamicProxyPattern {
public static void main(String[] arg){
PersonnelDepartment personnelDepartment = new PersonnelDepartment();
Department mAdvertisingDepartment = (Department) personnelDepartment.newProxyInstance(new AdvertisingDepartment());
mAdvertisingDepartment.Negotiate();
mAdvertisingDepartment.Sign();
Department mProductDepartment = (Department) personnelDepartment.newProxyInstance(new ProductDepartment());
mProductDepartment.Negotiate();
mProductDepartment.Sign();
}
}
结果:
人事部准备场地
人事部邀请应聘者面试谈判
广告部正在和应聘者谈判
谈判成功,人事部制定合同
1.
----------------
人事部准备场地
人事部邀请应聘者面试签约
广告部和应聘者签好了合约
签约成功,人事部安排新同事上班
----------------
人事部准备场地
人事部邀请应聘者面试谈判
产品部正在和应聘者谈判
谈判成功,人事部制定合同
----------------
人事部准备场地
人事部邀请应聘者面试签约
产品部和应聘者签好了合约
签约成功,人事部安排新同事上班
----------------
动态代理模式的应用场景其实和静态代理的差不多,只是如果静态代理要代理的对象比较多的时候,就建议使用动态代理,可以减少很多重复的代码。
标签:
原文地址:http://blog.csdn.net/totond/article/details/51811462