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

    代理模式定义:为其它对象提供一种代理以控制对这个对象的访问。代理的目的是在目标对象方法的基础上做增强,这种增强的本质是对目标方法做过滤和拦截。比如租房者找房子这件事,租房者给中介1000元中介费,然后中介通过各种方法最终为租房者找到了房子,最后租房者签合同入住。对这个流程进行分析:角色有中介(目标对象),租房者(代理对象);动作有给中介1000元中介费,签合同入住 (这两个属于增强处理),中介通过各种方法找到了房子(目标对象的目标方法,具体的业务逻辑就在这)。再比如游戏代练者用玩家的账号帮他们打怪升级,然后收取费用这件事:角色有玩家或者说玩家账号(目标对象),代练者(代理对象);动作有打怪升级(目标对象的目标方法),收费(增强处理)。

    1.静态代理

    在静态代理中,目标对象和代理对象需要实现的共同接口,定义IGamePlayer接口

    public interface IGamePlayer {
        
        //登录
        void login();
        
        //打怪升级
        void hunt();
    }

    定义玩家(目标对象)

    public class GamePlayer implements IGamePlayer{
    
        String userName = "";
        
        public GamePlayer(String userName){
            this.userName = userName;
        }
        
        public void login() {
            System.out.println(userName + "登录游戏");
        }
    
        public void hunt() {
            System.out.println(userName + "正在打怪升级");
        }
    
    }

    定义代练者(代理对象)

    public class ProxyGamePlayer implements IGamePlayer{
    
        //玩家(目标对象)
        IGamePlayer gamePlayer = null;
        
        public ProxyGamePlayer(IGamePlayer gamePlayer){
            this.gamePlayer = gamePlayer;
        }
        
        //登录账号
        public void login() {
            this.gamePlayer.login();
        }
    
        //打怪升级
        public void hunt() {
            this.gamePlayer.hunt();
            this.charge(); //增强处理
        }
        
        //收费
        public void charge(){
            System.out.println("收费5元");
        }
    
    }

    定义场景类:

    public class Client {
        public static void main(String[] args) {
            IGamePlayer gamePlayer = new GamePlayer("张三");//目标对象
            IGamePlayer proxyGamePlayer = new ProxyGamePlayer(gamePlayer);//代理对象
            proxyGamePlayer.login();
            proxyGamePlayer.hunt();
        }
    }

    静态代理由于目标对象和代理对象需要实现共同的接口,所有会有很多代理对象,并且当接口中增加方法时,也要进行相应的维护,所以这一点不太好。有问题就有解决办法的,接下来我们就介绍动态代理。

    2.JDK动态代理

    我们先定义GamePlayer,IGamePlayer,同静态代理中的一样。然后定义一个InvocationHandler接口的实现类,用于代理对象的生成。

    public class GamePlayerIH implements InvocationHandler{
    
        //被代理的对象
        Object obj = null;
        
        //我要代理谁
        public GamePlayerIH(Object _obj){
            this.obj = _obj;
        }
        
        //调用被代理的方法
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            Object result = method.invoke(obj, args); //调用目标对象的目标方法
            if(method.getName().equals("login")){
                System.out.println("我的账号被别人登录了");//增强处理
            }
            return result;
        }
    
    }

    然后定义一个场景类:

    public class Client {
        public static void main(String[] args) {
            //目标对象
            IGamePlayer gamePlayer = new GamePlayer("张三");
            InvocationHandler invocationHandler = new GamePlayerIH(gamePlayer);
            //代理对象
            IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(gamePlayer.getClass().getClassLoader(), gamePlayer.getClass().getInterfaces(), invocationHandler);
            proxy.login();
        }
    }

    jdk动态代理的前提条件是被代理者需要实现一个接口。那么如果一个目标对象没有实现任何接口,该如何实现代理呢?Cblib代理可以解决这个问题。

    3.Cglib代理

    cglib代理不需要目标对象实现任何接口,它是以目标对象子类的方式来实现代理的,也就是说目标对象的代理类就是它的子类。

    定义GamePlayer类,不需要实现任何接口,注意,这个类一定要有一个默认的构造器。

    public class GamePlayer{
    
        String userName = "";
        
        public GamePlayer(String userName){
            this.userName = userName;
        }
        
        public GamePlayer(){
            
        }
        
        public void login() {
            System.out.println(userName + "登录游戏");
        }
    
        public void hunt() {
            System.out.println(userName + "正在打怪升级");
        }
    
    }

    定义Cglib子类代理工厂,用于生成目标对象的代理对象(子类对象)

    public class ProxyFactory implements MethodInterceptor{
    
        //目标对象
        private Object obj = null;
        
        //要代理的是目标对象
        public ProxyFactory(Object _obj){
            this.obj = _obj;
        }
        
        //给目标对象创建一个代理对象
        public Object getProxyInstance(){
            Enhancer enhancer = new Enhancer();//工具类
            enhancer.setSuperclass(obj.getClass());//设置父类
            enhancer.setCallback(this);//设置回调函数
            return enhancer.create();//创建子类(代理对象)
        }
        
        //调用目标对象的目标方法
        public Object intercept(Object arg, Method method, Object[] args,
                MethodProxy arg3) throws Throwable {
            Object returnObject =  method.invoke(obj, args);//调用目标对象的目标方法
            if(method.getName().equals("login")){
                System.out.println("我的账号被别人登录了");//增强处理
            }
            return returnObject;
        }
    
    }

    定义场景类

    public class Client {
        public static void main(String[] args) {
            //目标对象
            GamePlayer gamePlayer = new GamePlayer("张三");
            //代理对象
            GamePlayer proxy = (GamePlayer) new ProxyFactory(gamePlayer).getProxyInstance();
            proxy.login();
        }
    }

    总结:静态代理中,目标对象和代理对象需要实现相同的接口;JDK动态代理中,目标对象至少需要实现一个接口,而代理对象不必实现接口;Cglib代理中,目标对象和代理对象都不需要实现接口,代理对象就是目标对象的子类对象,由于子类覆盖了目标对象的方法,所以目标对象和方法都不能是final类型。从效率上来比较:JDK动态代理使用的是java反射机制来实现的,效率较低。cglib使用的是java字节码框架ASM来生成代理对象的字节码文件,效率较高。

  • 相关阅读:
    Android开发经验一判断当前屏幕是全屏还是非全屏
    Android得到控件在屏幕中的坐标
    MyBatis简单的增删改查以及简单的分页查询实现
    Coreseek:第二步建索引及測试
    极静之渊
    统计电影票房排名前10的电影并存入还有一个文件
    AAA
    FreeLink开源呼叫中心设计思想
    树后台数据存储(採用webmethod)
    [乐意黎原创] 百度统计这个坑爹货
  • 原文地址:https://www.cnblogs.com/51life/p/9224555.html
Copyright © 2011-2022 走看看