设计模式之代理模式Proxy

tech2024-10-11  24

1.问题引入

租房问题: 房东想要把房子租出去,那么他需要做两件事:1.带人去看房子;2.签合同收租金,把房子交出去. 租客想要租房子:那么他需要做两件事:1.去看房子;2.签合同交租金,拿到房子. 但是现在,房东嫌麻烦,不想带人去看房子,只想签合同收租金,把房子交出去.但是对租客来说,肯定只有看了房子之后才知道满不满意,才能确定要不要签合同交租金. 所以自然而然就有了一种行业:中介.房东把房子交给中介,有租客想要租房的时候,中介带领租客去看房子,租客想要签合同拿房子的时候,中介把房东叫过来,签合同交房子. 这其实就是一个很典型的代理.

2.代理模式的定义.

定义:为其他对象 提供一种代理以控制对这个对象的访问.

代理模式的结构和说明: 代理模式主要有三个角色:

client 客户端,相当于前面例子中的租客.RealSubject 真实对象,也叫目标对象,相当于前面例子中的房东.Proxy 代理对象,相当于前面例子中的中介.代理对象中持有真实对象的实例,代理对象方法的实现,最终是通过调用真实对象的方法来实现的.就相当于例子中的签合同,交房子.中介是没有房子的,最终交给租客是房东的房子.

注意到:真实对象RealSubject和代理对象Proxy实现了同一个接口,这是为什么呢?想想,如果代理对象只有真实对象的部分方法,那还能叫代理吗?代理对象想要代理真实对象,那真实对象有的方法代理对象也必须要有.如何保证代理对象有真实对象的所有方法,那就是实现同一个接口喽.真实对象有的方法代理对象全都有,这样就可以完全代理了.

代码示例:

/** * 抽象的目标接口,目标对象和代理对象公用的接口 */ public interface Subject { /** * 看房子 */ public void seeHouse(); /** * 签合同 */ public void signContract(); } ======================================= /*** * 具体的目标对象,是真正被代理的对象 房东 */ public class LandLord implements Subject { @Override public void seeHouse() { System.out.println("带人来看看房子"); } @Override public void signContract() { System.out.println("签合同收钱了"); } } ================================ /*** * 代理对象 中介 */ public class Proxy implements Subject { /** * 持有被代理的具体的目标对象 */ private LandLord landLord = null; /** * 构造方法,传入被代理的具体的目标对象 * @param landLord */ public Proxy(LandLord landLord) { this.landLord = landLord; } @Override public void seeHouse() { // 在调用具体的方法前可以执行的一些操作 System.out.println("我是中介,我领的人来看房"); //调用具体的目标对象方法 landLord.seeHouse(); // 在调用具体的方法后可以执行的一些操作 System.out.println("我是中介,我领人看完房子了"); } @Override public void signContract() { // 在调用具体的方法前可以执行的一些操作 System.out.println("我是中介,我领的人来看签合同"); //调用具体的目标对象方法 landLord.signContract(); // 在调用具体的方法后可以执行的一些操作 System.out.println("我是中介,我领人签完合同了"); } } ============================================ /*** * 租客 */ public class Tenant { public static void main(String[] args) { // 找中介 Proxy proxy = new Proxy(new LandLord()); //看房 proxy.seeHouse(); System.out.println("========看房满意++++++++"); // 签约 proxy.signContract(); } } 输出结果: 我是中介,我领的人来看房 带人来看看房子 我是中介,我领人看完房子了 ========看房满意++++++++ 我是中介,我领的人来看签合同 签合同收钱了 我是中介,我领人签完合同了

3.认识代理模式

代理模式是通过创建一个代理对象,用这个代理对象那个去代表真实的对象,客户端得到这个代理对象后,对客户端没什么影响,就跟得到一个真实的对象一样去使用.当客户端得到这个代理对象的时候,实际上功能最终还是由真实对象来完成. 正是因为代理对象夹在客户端和真实对象之间,相当于一个中转,那么中转的时候就可以做很多其他的事情. 代理模式的调用顺序图:

4.java中的代理

java对代理模式提供的内建的支持,在java.lang.reflect包下,提供了一个Proxy和一个InvocationHandler接口.

通常前面的那种自己实现代理的方式称为静态代理.静态代理一个很大的弊端就是,一旦Subject接口发生变化,真实对象和代理对象都要相应发生变化.一个真实对象对应一个代理类,类的数量很多,维护不易. 通常把java内建的对代理模式支持的功能来实现的代理称为动态代理.动态代理和静态代理很明显的变化是:静态代理实现是,Subject接口有很多方法,代理类自然也要实现很多方法.动态实现的时候,虽然Subject接口定义了很多方法,但是动态代理类始终只有一个invoke()方法.这样在Subject接口变化的时候,动态代理却不用跟着变化了.

java的动态代理目前只能代理接口,基本实现是依靠java的反射和动态生成class文件的技术,来生成被代理接口的实现对象.如果实现类的代理,可以使用cglib.

使用动态代理改写前面的例子:

接口和真实对象完全一样,不做更改 // 新的动态代理类 /** * 使用java中的动态代理 */ public class DynamicProxy implements InvocationHandler { /** * 被代理的真实对象 */ private LandLord landLord = null; /** * 获取绑定好代理和真实对象后的真实对象的接口 * @return */ public Subject getProxyInterface(LandLord landlord){ // 设置好被代理的对象,方便invoke里操作 this.landLord = landlord; // 把真正的对象和代理对象关联起来. Subject subject = (Subject)Proxy.newProxyInstance(landlord.getClass().getClassLoader(), landlord.getClass().getInterfaces(), this); return subject; } /** * proxy:  指代我们所代理的那个真实对象 * method:  指代的是我们所要调用真实对象的某个方法的Method对象 * args:  指代的是调用真实对象某个方法时接受的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是中介"); return method.invoke(landLord,args); } } ============================= public class Tenant { public static void main(String[] args) { DynamicProxy dynamicProxy = new DynamicProxy(); Subject proxyInterface = dynamicProxy.getProxyInterface(new LandLord()); proxyInterface.seeHouse(); proxyInterface.signContract(); } } 输出: 我是中介 带人来看看房子 我是中介 签合同收钱了
最新回复(0)