资讯专栏INFORMATION COLUMN

代理模式

keithxiaoy / 2768人阅读

摘要:简介代理模式委托模式就是使用代理对象来访问目标对象这样可以在目标对象执行前后来做一些逻辑处理这里使用到编程中的一个思想不要随意去修改别人已经写好的代码或者方法如果需改修改可以通过代理的方式来扩展该方法代理模式通用类图设计模式之禅文中提到为其

简介

代理模式(委托模式)就是使用代理对象来访问目标对象, 这样可以在目标对象执行前后, 来做一些逻辑处理.

这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法.

代理模式通用类图

《设计模式之禅》文中提到: 为其它对象提供一种代理以控制对这个对象的访问.
静态代理

静态代理在使用时, 需要定义接口或者父类, 被代理对象与代理对象一起实现相同的接口或者是继承相同父类.

接口: IUserDao.java

/**
 * 抽象主题类可以是抽象类也可以是接口, 是一个普通的业务类型定义, 无特殊要求.
 */
public interface IUserDao {

    void save();
}

目标对象: UserDao.java

/**
 * 抽象主题实现类
 * 也叫做被委托角色 被代理角色. 是业务逻辑的具体执行者.
 */
public class UserDao implements IUserDao {
    public void save() {
        System.out.println("----已经保存数据!----");
    }
}

代理对象: UserDaoProxy.java

/**
 * 代理主题角色
 * 也叫做委托类 代理类. 它负责对真实主题角色处理完毕前后做预处理和善后工作.
 */
public class UserDaoProxy implements IUserDao{
    //接收保存目标对象
    private IUserDao target;
    public UserDaoProxy(IUserDao target){
        this.target=target;
    }

    public void save() {
        System.out.println("开始事务...");
        target.save();//执行目标对象的方法
        System.out.println("提交事务...");
    }
}

测试类: App.java

/**
 * 测试类
 */
public class App {
    public static void main(String[] args) {
        //目标对象
        UserDao target = new UserDao();

        //代理对象,把目标对象传给代理对象,建立代理关系
        UserDaoProxy proxy = new UserDaoProxy(target);

        proxy.save();//执行的是代理的方法
    }
}
静态代理总结

1.可以做到在不修改目标对象的功能前提下, 对目标功能扩展.
2.缺点:

因为代理对象需要与目标对象实现一样的接口, 所以会有很多代理类, 类太多. 同时, 一旦接口增加方法, 目标对象与代理对象都要维护.

动态代理

动态代理是指在运行时动态生成代理类. 即, 代理类的字节码将在运行时生成并载入当前代理的 ClassLoader. 现在有一个非常流行的名称叫做面向横切面编程, 也就是 AOP.

JDK 实现动态代理

使用 GamePlayIH 来实现 InvocationHandler 接口, 作用就是产生一个对象的代理对象.

动态代理不像静态代理那样我们需要手动来创建一个代理对象, 而是在运行时帮我们生成一个代理对象.

InvocationHandler 是动态代理接口, 主要代理要被代理的方法. 其中 invoke 方法, 主要完成对真实方法的调用.

我们将 UserDaoProxy 类改为实现 InvocationHandler 接口.

public class UserDaoProxy implements InvocationHandler {

    private static String SAVE = "save";

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (SAVE.equals(method.getName())) {
            System.out.println("这句代码表示 save 方法实现类中的业务逻辑.");
        }
        return null;
    }
}

通过 Proxy.newProxyInstance 方法来帮我们创建代理对象, 第二个参数表示代理类要实现的接口列表, 第三个参数是实现 InvocationHandler 接口的类, 就是用来处理我们接口列表中接口的所有方法的.

public class App {
    public static void main(String[] args) {
        IUserDao iUserDao = (IUserDao) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{IUserDao.class},
                new UserDaoProxy());

        iUserDao.save();
    }
}

代理对象不需要实现接口, 但是目标对象一定要实现接口, 否则不能用动态代理.

CGlib 实现动态代理

上面的静态代理和动态代理模式都是要求目标对象都要实现一个接口, 但是有时候目标对象只是一个多带带的对象, 并没有实现任何的接口, 这个时候就可以使用以目标对象子类的方式来实现代理, 这种方法就叫做: Cglib代理

Cglib代理, 也叫作子类代理, 它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

JDK 的动态代理有一个限制, 就是要使用动态代理的对象必须实现一个或多个接口.

Cglib 是一个强大的高性能的代码生成包, 它可以在运行期扩展java类与实现java接口. 它广泛的被许多 AOP 的框架使用, 例如 Spring AOP 和 synaop , 为他们提供方法的interception(拦截).

Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类. 不鼓励直接使用ASM, 因为它要求你必须对 JVM 内部结构包括 class 文件的格式和指令集都很熟悉.

使用 cglib 动态代理必须要注意, 目标对象的方法如果为 final/static, 那么就不会被拦截, 即不会执行目标对象额外的业务方法.

/**
 * 目标对象,没有实现任何接口
 */
public class UserDao {

    public void save() {
        System.out.println("----已经保存数据!----");
    }
}
/**
 * Cglib子类代理工厂
 * 对UserDao在内存中动态构建一个子类对象
 */
public class ProxyFactory implements MethodInterceptor{
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
    }
}
/**
 * 测试类
 */
public class App {

    @Test
    public void test(){
        //目标对象
        UserDao target = new UserDao();

        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();

        //执行代理对象的方法
        proxy.save();
    }
}
代理模式的优点

职责清晰. 真实的角色就是实现实际的业务逻辑, 不用关系其它非本职责的事务, 通过后期的代理完成一件事务, 结果就是编程简洁清晰.

高扩展性. 实现类中的一些方法可能随时发生变化, 只要代理类实现了接口, 不管实现类如何变化, 我们在不做任何修改的情况下就可以使用.

代理类不仅仅可以实现主题接口, 也可以实现其它接口完成不同的任务, 而代理的目的是在目标对象方法的基础上作增强, 这种增强的本质通常就是对目标对象的方法进行拦截和过滤.
链接

给女朋友讲解什么是代理模式
代理模式(Proxy Pattern)- 最易懂的设计模式解析
代理模式原理及实例讲解

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72607.html

相关文章

  • 我的Java设计模式-代理模式

    摘要:下面总结了它俩的异同相同点都需要实现同一个接口或者继承同一个抽象类,并且代理角色和装饰角色都持有被代理角色和构件角色的引用。 写完上一篇之后有小伙伴问我有没有写过代理模式,想看看我的理解。原本我的设计模式系列是按照创建型-行为型-结构型的顺序写下去的,既然小伙伴诚心诚意了,我就大发慈悲的穿插一篇代理模式。开玩笑,题外话。 说起代理模式,就不由得想起经纪人,说起经纪人,就想起了...对,...

    BWrong 评论0 收藏0
  • 设计模式|代理模式

    摘要:三二模式分析代理模式的示意图结构比较简单一般可以简化如下图所示。五总结在代理模式中,要求给某一个对象提供一个代理,并由代理对象控制对原对象的访问,其英文为是一种结构型模式。 一、写在前面 代理模式是常用的结构型设计模式之一、当我们直接访问某些对象存在问题时可以通过代理模式来间接访问,为了保证客户端使用的透明性、所访问的真实对象和代理对象都必须实现同一个接口。 二、代理模式动机与定义 某...

    QiShare 评论0 收藏0
  • 代理模式和装饰者模式

    摘要:简介代理模式和装饰者模式是两种常见的设计模式。这里通过构造函数的参数将被代理对象传入到代理中,也可以通过其它方式,如提供一个方法。下面是的代码输出首先依然是先创建一个需要被代理的对象,然后把它传入到的构造函数中。 简介 代理模式和装饰者模式是两种常见的设计模式。代理模式是为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以...

    NusterCache 评论0 收藏0
  • js设计模式 --- 代理设计模式

    摘要:代理设计模式代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式是常见的设计模式之一是指不直接调用实际的对象,而是通过代理对象,来间接的调用实际的对象。对象类定义了代理对象所代表的目标对象。 代理设计模式 代理模式:为其他对象提供一种代理以控制对这个对象的访问。代理模式是常见的设计模式之一,是指不直接调用实际的对象,而是通过代理对象,来间接的调用实际的对象。为什么要采用这种间...

    Tonny 评论0 收藏0
  • 深入理解代理模式

    摘要:代理模式代理类中创建一个真实对象的实例模式的核心装饰者强调的是增强自身,在被装饰之后你能够在被增强的类上使用增强后的功能。 代理模式 在详细了解代理模式之前,可能对于像小秋一样的小白,只知道一些很浅显的概念,或者就知道远程代理啊,静态代理啊,动态代理啊,这些看似可以望文生义的专业名词,但是如果我告诉你代理模式贯穿了我们生活的方方面面,就比如你现在刷着公众号的时候,实际上就用了远程代理模...

    testHs 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<