设计模式---代理(Proxy)模式

1 定义

代理模式,为想要访问的对象创建一个代理,使访问原对象变为访问代理对象。代理模式可以提供非常好的访问控制。生活中最多的代理模式例子就是中介。

2 代理模式结构与实现

代理模式通用类图如下所示(来自《大话设计模式》):

  • Subject
    抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。
  • RealSubject
    具体主题角色:也叫做被委托角色被代理角色,是业务逻辑的具体执行者。
  • Proxy
    代理主题角色:也叫做委托类代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。

一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个具体主题角色,是由场景类决定的。最简单的情况是一个主题类和一个代理类。通常情况下,一个接口只需要一个代理类,具体代理哪个实现类有高层模块决定。

3 代理模式的优点

职责清晰

具体角色是实现具体的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,代码清晰。在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口

高扩展性

具体主题角色随时会发生变化,但是只要实现了接口,接口不变,代理类就可以不做任何修改继续使用,符合“开闭原则”。
另外,代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,同样符合开闭原则

4 静态代理

所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。淘宝商家卖货品,就是一个代理,用户想要买东西的时候,直接找淘宝卖家下单,就能买到心仪的货品。

4.1 卖货品接口Sell

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:58
 **/
public interface Sell {

    /**
     * 卖手套
     */
    String sellGloves();

    /**
     * 卖袜子
     */
    String sellSocks();

    /**
     * 卖鞋子
     */
    String sellShoes();
}

4.2 源商家YONEX

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:08
 **/
public class Yonex implements Sell {

    @Override
    public String sellGloves() {
        return "卖尤尼克斯的手套";
    }

    @Override
    public String sellSocks() {
        return "卖尤尼克斯的袜子";
    }

    @Override
    public String sellShoes() {
        return "卖尤尼克斯的鞋子";
    }
}

4.3 淘宝代理TaoBaoProxy

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:10
 **/
public class TaoBaoProxy implements Sell{
    private final Yonex yonex;

    private String COMMON_PEDDLE = "我是淘宝代理,";

    public TaoBaoProxy(){
        yonex = new Yonex();
    }

    @Override
    public String sellGloves() {
        return COMMON_PEDDLE + yonex.sellGloves();
    }

    @Override
    public String sellSocks() {
        return COMMON_PEDDLE + yonex.sellSocks();
    }

    @Override
    public String sellShoes() {
        return COMMON_PEDDLE + yonex.sellShoes();
    }
}

4.4 买家Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:24
 **/
public class Buyer {

    private TaoBaoProxy taoBao;

    public Buyer(){
        taoBao = new TaoBaoProxy();
    }

    public void buyGloves(){
        System.out.println("想要买手套");
        System.out.println(taoBao.sellGloves());
    }

    public void buySocks(){
        System.out.println("想要买袜子");
        System.out.println(taoBao.sellSocks());
    }

    public void buyShoes(){
        System.out.println("想要买鞋子");
        System.out.println(taoBao.sellShoes());
    }
}

4.5 主函数MainClass

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:56
 **/
public class MainClass {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

4.6 运行结果

4.7 总结 

静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。不足之处是静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。

5 动态代理

代理类在程序运行时创建的代理方式被成为动态代理。 我们上面静态代理的例子中,代理类(TaoBaoProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

本文介绍基于JDK的动态代理和基于CGLIB的动态代理。

5.1 基于JDK的动态代理

JDK动态代理,利用java.lang.reflect包下提供的一个Proxy类和一个InvocationHandler接口,Proxy用于动态生成代理类,InvocationHandler定义了实现代理类的方法。

代码实现中,业务与静态代理的业务相同,现在动态代理李宁旗下的鞋子袜子和手套。

5.1.1 卖货接口MySell

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:58
 **/
public interface MySell {

    /**
     * 卖手套
     */
    String sellGloves();

    /**
     * 卖袜子
     */
    String sellSocks();

    /**
     * 卖鞋子
     */
    String sellShoes();
}

5.1.2 李宁LiNing

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:08
 **/
public class LiNing implements MySell {

    @Override
    public String sellGloves() {
        return "卖李宁的手套";
    }

    @Override
    public String sellSocks() {
        return "卖李宁的袜子";
    }

    @Override
    public String sellShoes() {
        return "卖李宁的鞋子";
    }
}

5.1.3 实现InvocationHandler

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 11:55
 **/
public class MyInvocationHandler implements InvocationHandler {

    private MySell mySell;

    public MyInvocationHandler(MySell mySell){
        this.mySell = mySell;
    }

    /**
     *执行代理方法
     *
     * @param proxy 被动态代理的对象
     * @param method 代理执行的方法
     * @param args 执行的参数
     * @return method方法执行返回的参数
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是JDK淘宝代理");
        return method.invoke(mySell, args);
    }
}

5.1.4 用户买Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:24
 **/
public class Buyer {

    MySell mySell = new LiNing();

    public void buyGloves(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellGloves();
        System.out.println(result);;
    }

    public void buySocks(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellSocks();
        System.out.println(result);;
    }

    public void buyShoes(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellShoes();
        System.out.println(result);;

    }
}

5.1.5 主程序

public class MainClassJdk {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

5.1.6 运行结果

5.2 基于CGLIB的动态代理

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

代码实现的业务需求类似于JDK动态代理,现在买胜利的鞋子袜子和手套。

5.2.1 添加jar包

首先需要再idea添加cglib的jar包以及cglib依赖的asm jar包,jar包都可以在maven仓库中进行下载。

5.2.2 商铺类Victor

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:37
 **/
public class Victor {
    
    public String sellGloves() {
        return "卖胜利的手套";
    }

   
    public String sellSocks() {
        return "卖胜利的袜子";
    }

   
    public String sellShoes() {
        return "卖胜利的鞋子";
    }
}

5.2.3 CGLIB拦截器MyInterceptor

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:40
 **/
public class MyInterceptor implements MethodInterceptor {

    /**
     * 拦截方法
     *
     * @param o 代理的目标对象
     * @param method 目标对象的方法
     * @param objects 参数
     * @param methodProxy CGlib方法代理对象
     * @return 代理方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是CGLIB淘宝代理");
        return methodProxy.invokeSuper(o, objects);
    }
}

 5.2.4 买家Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:43
 **/
public class Buyer {

    public void buyGloves(){
        Victor victor = getVictor();
        System.out.println(victor.sellGloves());
    }

    public void buySocks(){
        Victor victor = getVictor();
        System.out.println(victor.sellSocks());
    }

    public void buyShoes(){
        Victor victor = getVictor();
        System.out.println(victor.sellShoes());

    }


    private Victor getVictor(){
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(Victor.class);
        enhancer.setCallback(new MyInterceptor());
        return (Victor) enhancer.create();
    }
}

5.2.5 主程序

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:48
 **/
public class MainClassCglib {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

5.2.6 执行结果

6 总结

本文主要介绍了设计模式中的代理模式,通过实际例子,编写代码实现了Java的静态代理,基于JDK的动态代理与基于CGLIB的动态代理。本文算是一个引入文章,后面背后强大的原理与代码分析,欢迎大家一起研究,一起进步。

7 引用

1.《大话设计模式》

2.java动态代理实现与原理详细分析

3.java动态代理详解

4.设计模式之——代理模式

5.CGLIB介绍与原理(通过继承的动态代理)

8 源码

https://github.com/airhonor/design-pattern-learning/tree/main/src/com/hz/design/pattern/proxy

猜你喜欢

转载自blog.csdn.net/honor_zhang/article/details/120175424