设计模式之代理模式Proxy

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值