zoukankan      html  css  js  c++  java
  • Java中的代理模式

    一、什么是代理模式?

           这里不做过多的理论解释,相关资料一大堆,只简单说下我理解的代理模式,代理模式的意思就是你想完成的工作不用自己完成,交给代理去帮你去完成。代理模式的案例生活中很常见,比如:毕业了在城市里工作,需要租房,大部分人都会接触到中介,通过中介租房,这里的中介在代理模式中就充当了代理的角色,中介代理真实房东带你去看房,有些权利大的中介,甚至会代理真实房东和你签合同。

    1.代理模式有什么好处?

    1).中介隔离

           还以上面租房为例:我是一位真实房东,家里有很多房产,打工是不可能打工的,平时就靠收收房租维持生活这样子。但是最近正好赶上毕业季,天天有租客联系我租房、看房,楼上楼下的跑是真累啊,而且还租不出去几套房子,这样的生活不能再持续下去了。于是我拨通了呗柯公寓的电话,希望呗柯公寓能够代理我的房子,帮我租出去,这样每天我就可以边收房租边好好呆在王者峡谷,不用每天去跟租客接触了。

    2).在遵循开闭原则的情况下,增加功能

           和呗柯公寓谈好价格后,我就等着房子租出去后,收租就行了,某一间房1500元每月,这是我跟呗柯公寓说好的价格。于是呗柯公寓的中介开始工作了,为了让租客对房子有一个很好的第一印象,负责的中介认真地打扫了整个房间,毕竟自己付出了劳动,也得给自己点回报,于是中介将房租价格加价200,打算以1700的价格出租出去,很快哈,房子就被租出去了,在我和租客签完合同后,中介又热心地帮助租客提运行李

           在上面租房的整个过程中,如果是我本人跟租客进行交涉,那么在签合同前,我不会打扫房间,也不会加价,也不会在合同签好之后,帮助租客提运行李,这些都是中介的附加行为,而我跟中介的唯一要求就是房子租出去签好合同,并且价格1500就行,中介的这些附加行为就相当于在不影响我的要求下(遵循开闭原则),增加的功能。

    二、静态代理

           静态代理是代理模式的一种,之所以会被称为静态代理,是因为还有个动态代理与之相对,下面直接以代码为例描述静态代理。

    两个单词
    Landlord:房东
    Agency:中介
    
    /**
     * 房东接口,不管每个月要1500还是每个月3000、5000的房东,都要签合同
     */
    public interface LandlordInterface {
    
        void sign();
    }
    
    /**
     * 每月要1500元的一个真实房东
     */
    public class Landlord implements LandlordInterface{
    
        @Override
        public void sign() {
            System.out.println("和租客签合同,1500元每月...");
        }
    }
    
    /**
     * 中介
     */
    public class Agency implements LandlordInterface{
    
        private Landlord landlord;
    
        public Agency(Landlord landlord) {
            this.landlord = landlord;
        }
    
        @Override
        public void sign() {
          	// 在和租客签合同前,中介的"附加行为"
            System.out.println("打扫房间...");
            System.out.println("将房间价格加价200...");
          	// 房东和租客签合同
            landlord.sign();
          	// 在和租客签合同后,中介的"附加行为"
            System.out.println("帮租客提运行李...");
        }
    }
    
    /**
     * 模拟租房过程的一个测试类
     */
    public class Test {
    
        public static void main(String[] args) {
            Landlord landlord = new Landlord();
            // 中介要完成房东的要求,要完成哪个房东要求?所以需要在构造方法中传入这个租金为1500元的房东
            Agency agency = new Agency(landlord);
            // 签合同
            agency.sign();
        }
    }
    

    运行测试类的结果:

    打扫房间...
    将房间价格加价200...
    真实房东和租客签合同,1500元每月...
    帮租客提运行李...
    

           以上代码描述的就是一个静态代理的过程,简单并且很容易理解。但是,如果这位房东不想自己收租了,于是把收租的权利也交给了中介,那么中介就要给自己添加一条收租行为;如果房东不想收水电费了,中介还要给自己添加一条收水电费的行为;如果房东...... 只要房东一有要求,那么中介类就要修改自己的行为(修改代码)。很显然,这种静态代理模式不是我们经常会用到的。

    三、动态代理

           动态代理分为JDK动态代理和Cglib动态代理,与静态代理相比较,从代码的角度看,代理类不再需要我们手动去创建了,而是根据被代理对象的需求动态生成一个代理对象。

    1.JDK动态代理

           JDK动态代理是Java提供的一种动态代理Api,要使用JDK动态代理,被代理对象需要实现一个接口,下面用代码演示一下动态代理的过程。

    /**
     * 房东接口
     */
    public interface LandlordInterface {
    
        void sign();
    }
    
    /**
     * 每月要1500元的一个真实房东
     */
    public class Landlord implements LandlordInterface{
    
        @Override
        public void sign() {
            System.out.println("和租客签合同,1500元每月...");
        }
    }
    
    /**
     * 使用JDK动态代理,需要编写一个类实现InvocationHandler接口
     */
    public class MyInvocationHandler implements InvocationHandler {
    
        /**
         * 被代理的对象(比如房东)
         */
        private Object target;
    
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          	// 中介每次在执行房东的任务前,都会加收租客费用
            System.out.println("加价收取租客费用...");
          	// 执行房东的任务(即执行房东对象对应的方法)
            Object result = method.invoke(target, args);
            return result;
        }
    }
    
    /**
     * 模拟租房过程的一个测试类
     */
    public class Test {
        public static void main(String[] args) {
    
            Landlord landlord = new Landlord();
            MyInvocationHandler invocationHandler = new MyInvocationHandler(landlord);
          	// 动态生成一个代理对象
            LandlordInterface proxy = (LandlordInterface) Proxy.newProxyInstance(
                landlord.getClass().getClassLoader(), 
                landlord.getClass().getInterfaces(), 
                invocationHandler);
          	// 执行签合同方法
            proxy.sign();
        }
    }
    
    

           如果房东只有一个签合同行为,动态代理和静态代理相比,虽然不用去写代理类了,但是需要编写一个InvocationHandler的实现类,这里并没有体现动态代理的动态性、便利性,但是,如果房东还将收水费、收电费、收房租也代理给中介,那么就能看到动态代理的便利性了。

    /**
     * 房东接口
     */
    public interface LandlordInterface {
    
        void sign();
        
        void waterCharge();
    }
    
    /**
     * 每月要1500元的一个真实房东
     */
    public class Landlord implements LandlordInterface{
    
        @Override
        public void sign() {
            System.out.println("和租客签合同,1500元每月...");
        }
      
      	@Override
        public void waterCharge() {
            System.out.println("收水费,每月10元...");
        }
    }
    

           这里,又给房东添加了一个收水费的行为,此时中介想要代理收水费行为并从中牟利,不需要修改任何代码,直接在测试类中使用即可。

    /**
     * 模拟租房过程的一个测试类
     */
    public class Test {
        public static void main(String[] args) {
    
            Landlord landlord = new Landlord();
            MyInvocationHandler invocationHandler = new MyInvocationHandler(landlord);
          	// 动态生成一个代理对象
            LandlordInterface proxy = (LandlordInterface) Proxy.newProxyInstance(
                landlord.getClass().getClassLoader(), 
                landlord.getClass().getInterfaces(), 
                invocationHandler);
          	// 执行签合同方法
            proxy.sign();
          	// 执行收水费方法
            proxy.waterCharge();
        }
    }
    

           如果使用静态代理的方式,还需要在中介类中添加对应的waterCharge()方法。

    2.Cglib动态代理

           通过上面JDK动态代理的实例可以看到,JDK动态代理依赖于被代理类对象(房东)需要实现一个接口(房东接口),如果被代理对象没有实现接口,那么就无法使用JDK动态代理了,这也是JDK动态代理和Cglib动态代理的区别之处。Cglib(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以动态地扩展Java类。Cglib动态代理示例:

    <!-- 使用cglib动态代理需要引入cglib依赖或者加入cglib相关jar包 -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2</version>
    </dependency>
    
    /**
     * 每月要1500元的一个真实房东 需要注意:本类没有实现接口
     */
    public class Landlord {
    
        public void sign() {
            System.out.println("和租客签合同,1500元每月...");
        }
    }
    
    /**
     * 使用Cglib动态代理,需要编写一个类实现MethodInterceptor接口
     */
    public class MyMethodInterceptor implements MethodInterceptor {
    
        private Enhancer enhancer = new Enhancer();
    
      	/**
      	 * clazz是被代理对象的类类型
      	 */
        public Object getProxy(Class<?> clazz){
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable 		{
          	// 中介每次在执行房东的任务前,都会加收租客费用
            System.out.println("加价收取租客费用...");
          	// 执行房东的任务(即执行房东对象对应的方法)
            Object result = methodProxy.invokeSuper(obj, args);
            return result;
        }
    }
    
    /**
     * 模拟租房过程的一个测试类
     */
    public class Test {
        public static void main(String[] args) {
          	MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
          	// 动态生成一个代理对象
            Landlord proxy = (Landlord) myMethodInterceptor.getProxy(Landlord.class);
          	// 执行签合同方法
            proxy.sign();
        }
    }
    

    题外话

           本文拿中介租房作为一个代理模式的例子举例,对于中介加价的行为可能冒犯了中介从事者,我在此表示歉意。中介和我一样都是打工人,也很不容易,我第一次租房就是通过中介,接触到不少中介,并没有觉得租房过程有什么不舒服的地方,反倒他们的热情会让我愧疚我的租金给少了。。。还望看到这里的同学不要对中介有敌意。

  • 相关阅读:
    2. Add Two Numbers
    1. Two Sum
    leetcode 213. 打家劫舍 II JAVA
    leetcode 48. 旋转图像 java
    leetcode 45. 跳跃游戏 II JAVA
    leetcode 42. 接雨水 JAVA
    40. 组合总和 II leetcode JAVA
    24. 两两交换链表中的节点 leetcode
    1002. 查找常用字符 leecode
    leetcode 23. 合并K个排序链表 JAVA
  • 原文地址:https://www.cnblogs.com/BoildWater/p/14103487.html
Copyright © 2011-2022 走看看