• 自解代理模式


    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。

    http://www.cnblogs.com/shijiaqi1066/p/4762995.html

    代理模式:为对象提供一种代理,以控制对这个对象的访问。

    代理模式的作用:

    1. 职责清晰。真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
    2. 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
    3. 高扩展性。

    以上的废话都来自百度百科。如果不真正敲代码,是不能真正理解到代理模式的好处的。

    实现代理模式比较简单,可代理模式却真正能对代码做出很多有效的扩展,并且可以高效的复用代码。

    首先有一个行为接口。该接口用于定义需要代理的动作。

    public interface Shopping {
        void shopping();
    }

    试想普通人去超市买东西。一般买东西有个过程,即“去商场”“购物”“回家”。

    一般来说,例如有三类人,美女,男生,大妈。他们都要买东西,但买的东西都不同。

    class BeautifulGirl implements Shopping {
        @Override
        public void shopping() {
            System.out.println("买鞋子");
        }
    }
    
    class SchoolBoy implements Shopping {
        @Override
        public void shopping() {
            System.out.println("买玩具");
        }
    }
    
    class SquareDanceAunt implements Shopping {
        @Override
        public void shopping() {
            System.out.println("买衣服");
        }
    }

    这些买东西的人要买东西,他们都需要先“去商场”最后“回家”。那么就需要扩展以上代码。

    传统思路

    那么一般“扩展”方法如下:

    class BeautifulGirl implements Shopping {
        @Override
        public void shopping() {
            System.out.println("去商场");
            System.out.println("买鞋子");
            System.out.println("回家");
        }
    }
    
    class SchoolBoy implements Shopping {
        @Override
        public void shopping() {
            System.out.println("去商场");
            System.out.println("买玩具");
            System.out.println("回家");
        }
    }
    
    class SquareDanceAunt implements Shopping {
        @Override
        public void shopping() {
            System.out.println("去商场");
            System.out.println("买衣服");
            System.out.println("回家");    
        }
    }

    现在,我们命令这些人去买东西,执行如下:

    public class World {
        public static void main(String[] args) {
            Shopping beautifulGirl = new BeautifulGirl();
            Shopping schoolBoy = new SchoolBoy();
            Shopping squareDanceAunt = new SquareDanceAunt();
            
            beautifulGirl.shopping();
            schoolBoy.shopping();
            squareDanceAunt.shopping();
        }
    }

    这种修改方法违反了开闭原则与DRY原则。

    可以直观的感受到,其中以下代码需要重复写,很累。

    System.out.println("去商场");
    // ......
    System.out.println("回家");    

    静态代理

    我们需要给这些人提供一个代理,让代理去简化买东西的过程,把“去商场”,“回家”这个过程却都有代理去做了。

    现实中,这种代理一般我们喜欢叫他雷锋。

    public class LeiFengProxy implements Shopping {
        
        /**
         * 雷锋侠要服务的对象。
         */
        private Shopping shoper;
        
        /**
         * 召唤雷锋侠。
         * @param shoper
         */
        public LeiFengProxy(Shopping shoper){
            this.shoper = shoper;
        }
    
        @Override
        public void shopping() {
            System.out.println("去商场");
            shoper.shopping();
            System.out.println("回家");
        }
    
    }

    有了雷锋这种代理,让这些人去买东西就轻松很多了。

    public class World {
        public static void main(String[] args) {
            Shopping beautifulGirl = new BeautifulGirl();
            Shopping schoolBoy = new SchoolBoy();
            Shopping squareDanceAunt = new SquareDanceAunt();
            
            Shopping beautifulGirlProxy = new LeiFengProxy(beautifulGirl);
            Shopping schoolBoyProxy = new LeiFengProxy(schoolBoy);
            Shopping squareDanceAuntProxy = new LeiFengProxy(squareDanceAunt);
            
            beautifulGirlProxy.shopping();
            schoolBoyProxy.shopping();
            squareDanceAuntProxy.shopping();
            
        }
    }

    让每个人的代理雷锋去买东西,实际上代理雷锋操作了买东西的这个人,

    这种修改精简了代码,不再需要重复写“去商场”“回家”,而且符合开闭原则与DRY。

    动态代理

    一般动态代理直接使用JDK的动态代理。将与Shopping这个动作的无关的动作直接封装起来。

    public class GoShopHandler implements InvocationHandler {
        
        /**
         * 服务对象
         */
        private Object object;
        
        public GoShopHandler(Object object){
            this.object = object;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("去商场");
            method.invoke(object,args);
            System.out.println("回家");
            return null;
        }
    
    }

    不再需要写代理类。直接生成代理对象。

    public class World {
        public static void main(String[] args) {
            Shopping beautifulGirl = new BeautifulGirl();
            Shopping schoolBoy = new SchoolBoy();
            Shopping squareDanceAunt = new SquareDanceAunt();
            
            Shopping beautifulGirlProxy = (Shopping) Proxy.newProxyInstance(beautifulGirl.getClass().getClassLoader(), beautifulGirl.getClass().getInterfaces(), new GoShopHandler(beautifulGirl));
            Shopping schoolBoyProxy = (Shopping) Proxy.newProxyInstance(schoolBoy.getClass().getClassLoader(), schoolBoy.getClass().getInterfaces(), new GoShopHandler(schoolBoy));
            Shopping squareDanceAuntProxy = (Shopping) Proxy.newProxyInstance(squareDanceAunt.getClass().getClassLoader(), squareDanceAunt.getClass().getInterfaces(), new GoShopHandler(squareDanceAunt));
            
            beautifulGirlProxy.shopping();
            schoolBoyProxy.shopping();
            squareDanceAuntProxy.shopping();
            
        }
    }

    使用动态代理中扩展代码与原始对象的接口无关。即动态代理比静态代理的优势在于GoShopHandler可以扩展任意“到商场去”的动作,不一定要局限于Shopping。也有可能有些人去商场是去工作的,比如营业员。

    public interface Working {
        void working();
    }
    public class SalesClerk implements Working {
        @Override
        public void working() {
            System.out.println("上班");
        }
    }

    结合GoShopHandler扩展营业员的Working动作。

    public class World {
    	public static void main(String[] args) {
    		Shopping beautifulGirl = new BeautifulGirl();
    		Shopping schoolBoy = new SchoolBoy();
    		Shopping squareDanceAunt = new SquareDanceAunt();
    		SalesClerk salesClerk = new SalesClerk();
    		
    		Shopping beautifulGirlProxy = (Shopping) Proxy.newProxyInstance(beautifulGirl.getClass().getClassLoader(), beautifulGirl.getClass().getInterfaces(), new GoShopHandler(beautifulGirl));
    		Shopping schoolBoyProxy = (Shopping) Proxy.newProxyInstance(schoolBoy.getClass().getClassLoader(), schoolBoy.getClass().getInterfaces(), new GoShopHandler(schoolBoy));
    		Shopping squareDanceAuntProxy = (Shopping) Proxy.newProxyInstance(squareDanceAunt.getClass().getClassLoader(), squareDanceAunt.getClass().getInterfaces(), new GoShopHandler(squareDanceAunt));
    		Working salesClerkProxy = (Working) Proxy.newProxyInstance(salesClerk.getClass().getClassLoader(), salesClerk.getClass().getInterfaces(), new GoShopHandler(salesClerk));
    		
    		beautifulGirlProxy.shopping();
    		schoolBoyProxy.shopping();
    		squareDanceAuntProxy.shopping();
    		salesClerkProxy.working();
    		
    	}
    }
    

    总结一下,代理模式的思想是创建一个代理对象,使用这个对象去操作原始对象(被代理的对象)。从而起到扩展原始对象的动作的目的。并且可以把与原始对象无关的扩展代码抽象到一起去。

    代理模式的是AOP的基础,其效果有点像与Windows编程中的Hook技术,只不过这里是面向对象的。

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处。LaplaceDemon/ShiJiaqi。

    http://www.cnblogs.com/shijiaqi1066/p/4762995.html

  • 相关阅读:
    Linux中使用dd制作文件的.img
    python正则表达式
    使用@property
    Win10添加删除虚拟打印机方法
    jenkins权限
    RedHat7.2下Jenkins的安装配置
    jenkins忘记管理员账号密码的补救方法
    RHEL软件安装
    docker 常用指令(RHLE)
    /var/run/yum.pid 已被锁定,PID 为 4242 的另一个程序正在运行
  • 原文地址:https://www.cnblogs.com/shijiaqi1066/p/4762995.html
Copyright © 2020-2023  润新知