代理模式

Posted 51life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式相关的知识,希望对你有一定的参考价值。

代理模式定义:为其它对象提供一种代理以控制对这个对象的访问。代理的目的是在目标对象方法的基础上做增强,这种增强的本质是对目标方法做过滤和拦截。比如租房者找房子这件事,租房者给中介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代理中,目标对象和代理对象都不需要实现接口,代理对象是根据目标对象的子类来生成的。

以上是关于代理模式的主要内容,如果未能解决你的问题,请参考以下文章

scrapy按顺序启动多个爬虫代码片段(python3)

用于从 cloudkit 检索单列的代码模式/片段

java代码实现设计模式之代理模式

代理模式(静态代理动态代理)代码实战(详细)

Java设计模式-代理模式之动态代理(附源代码分析)

代理模式(静态代理)