代理模式

代理模式(Proxy Pattern)属于结构型模式。

它是指为其他对象提供一种代理以控制对这个对象的访问。

在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

在代理模式中,创建具有现有对象的对象,以便向外界提供功能接口。

想在访问一个类时做一些控制的时候就可以是用代理模式。

分类

代理模式属于结构型模式,分为静态代理和动态代理。

1.静态代理:静态定义代理类

静态代理需要自己生成代理类

2.动态代理:动态生成代理类

动态代理不用亲自去实现,通常使用现成的API即可。目前普遍使用的是JDK自带的代理与CGLIB提供的类库。

主要角色

代理模式一般包含三种角色:

1.抽象主题角色(Subject)

抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类

2.真实主题角色(RealSubject)

该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的罗辑业务对象

3.代理主题角色(Proxy)

代理主题也被称为代理类,其内部特有RealSubject的引用,因此具备完全的对RealSubject的代理权。

客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码。可以理解为代码增强,实际上就是在原代码罗辑前后增加一些代码逻辑,而使调用者无感知。

作用

1.保护目标对象,将代理对象与真实被调用目标对象分离

2.增强目标对象

3.降低系统耦合性,提升扩展性

静态代理与动态代理的区别

1.静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违背开闭原则。

2.动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原测。

3.若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无须修改代理类的代码。

静态代理的基本使用

静态代理需要自己生成代理类

创建抽象主题

public interface ISubject {
    /**
     * 买票
     */
    void buyTickets();
}

创建真实主题

public class RealSubject implements ISubject {
    public void buyTickets() {
        System.out.println("进行买票操作");
    }
}

创建代理主题

public class Proxy implements ISubject {
    private ISubject subject;
    public Proxy(ISubject subject) {
        this.subject = subject;
    }
    public void buyTickets() {
        before();
        subject.buyTickets();
        after();
    }
    public void before() {
        System.out.println("买票前的操作");
    }
    public void after() {
        System.out.println("买票后的操作");
    }
}

客户端调用

    public static void main(String[] args) {
        Proxy proxy = new Proxy(new RealSubject());
        proxy.buyTickets();
    }

买票前的操作
进行买票操作
买票后的操作

JDK动态代理的基本使用

创建抽象主题

public interface IUser {
    /**
     * 购物
     */
    void shopping();
}

创建真实主题

public class User implements IUser{
    @Override
    public void shopping() {
        System.out.println("user shopping....");
    }
}

创建代理主题

public class JDKProxy implements InvocationHandler {
    private Object tarjet;
    public JDKProxy(Object tarjet) {
        this.tarjet = tarjet;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理user,执行shopping()开始...");
        Object oj = method.invoke(tarjet, args);
        System.out.println("代理user,执行shopping()结束...");
        return oj;
    }
}

客户端调用

    public static void main(String[] args) {
        User user = new User();
        JDKProxy jdkProxy = new JDKProxy(user);
        IUser proxyInstance = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), jdkProxy);
        proxyInstance.shopping();
    }

代理user,执行shopping()开始...
user shopping....
代理user,执行shopping()结束...

小优化

在调用时候,传入了一推参数,可进一步优化

public class JDKProxy implements InvocationHandler {
    private Object tarjet;
    public Object JDKProxy(Object target){
        this.tarjet = target;
        Class<?> clazz =  target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理user,执行shopping()开始...");
        Object oj = method.invoke(tarjet, args);
        System.out.println("代理user,执行shopping()结束...");
        return oj;
    }
}
    public static void main(String[] args) {
        JDKProxy jdkProxy = new JDKProxy();
        IUser user= (IUser)jdkProxy.JDKProxy(new User());
        user.shopping();
    }

CGLIB动态代理的基本使用

CGLIB动态代理也不需要生成代理类,实现MethodInterceptor 就可以了。

注意:CGLib不能代理final的方法

创建抽象主题

注意:CGLb代理的目标对象不需要实现任何接口,就可以通过动态继承目标对象实现动态代理。所以此处可以不用创建接口。直接使用真实主题。

public interface IUser {
    public void shopping();
}

创建真实主题

public class User implements IUser{
    @Override
    public void shopping() {
        System.out.println("user shopping....");
    }
}

直接使用真实主题。

public class User {
    public void shopping() {
        System.out.println("user shopping....");
    }
}

创建代理主题

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理user,执行shopping()开始...");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("代理user,执行shopping()结束...");
        return invokeSuper;
    }
}

客户端调用

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(User.class);
        enhancer.setCallback(cglibProxy);
        IUser iUser = (IUser) enhancer.create();
        iUser.shopping();
    }

小优化

在客户端调用时,稍显复杂,可进一步优化

public class CglibProxy implements MethodInterceptor {
    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于Proxy,代理工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理user,执行shopping()开始...");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("代理user,执行shopping()结束...");
        return invokeSuper;
    }
}
    public static void main(String[] args) throws Exception {
        IUser user = (IUser) new CglibProxy().getInstance(User.class);
        user.shopping();
    }

CGLIB与JDK动态代理区别

1.执行条件

JDK动态代理实现了被代理对象的接口。CGLb代理的目标对象不需要实现任何接口,它是通过动态继承目标对象实现动态代理。

2.实现机制

JDK动态代理调用代理方法是由Java内部的反射机制来实现的,需要读取接口信息。CGLib动态代理是通过FastClass机制来实现的,需要覆盖父类方法。

3.性能

首先都在运行期生成字节码。

JDK动态代理的代理逻辑简单,直接写Class字节码,使用反射机制在生成类的过程中比较高效。

CGLib代理实现更复杂,使用ASM框架写Class字节码,但是asm在生成类之后的相关执行过程中比较高效。但是可以通过将asm生成的类进行缓存,解决asm生成类过程低效问题。

一句话:CGLib生成代理类比JDK动态代理效率低,但是执行效率比JDK动态代理高。

到此这篇关于Java结构型设计模式中代理模式示例详解的文章就介绍到这了,更多相关Java代理模式内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java结构型设计模式中代理模式示例详解的更多相关文章

  1. ios – UITextFieldDelegate vs UITextField控件事件

    处理编辑开始或编辑结束的相同问题.它可以通过适当的委托方法或适当的事件来完成.如果控件事件可以进行必要的工作,那么textField代理是什么?

  2. swift详解之十一------------协议、委托(代理)模式

    协议、委托(代理)模式注:本小节总结协议以及依靠协议实现委托,这将在以后经常被使用。很简单的例子说明下,在协议中用static在实现类里可以用static或者class在协议中使用mutating变异方法。然后他就一共实现了两个协议,一个sayHello一个hmtl的这时候这两个方法就都可以用了当然我们的协议也是可以继承的。

  3. Swift 委托/代理设计模式

    Swift中的委托/代理模式与object-c的代理模式基本一致。代理模式的基本思想就是将我需要来完成的工作交给(委托给)另一个有我所规定的做这项工作能力的人来处理。代理模式的实现需借助于我们上一篇文章所讲的协议。比如说我找到了玛雅房屋让他们去帮我租租房。我只需要告诉他们我要一个大致什么位置,多大,什么类型,价格范围等,他们就可以帮我去租房。玛雅房屋就是接受委托的对象,因为他有满足我要求的能力。

  4. Swift实现委托代理的N种方式

    首先理清概念,delegate只是一种模式理念,不是具体方法。OK1.extension继承法:赋予某根类扩展“空方法”,使其子类继承后可重写成为代理。就要你成为我的奴隶2.protocal协议法:只要实现了指定protocal即可成为代理下蛋的鸡就是好鸡3.闭包+Tuple代理:swift中方法也是firstclassvalue这不是人,这不是妖,这是人妖4.继承NSObject使用methodForSelector,使用OC中NSObject提供的的“反射”机制完成调用无耻下作的典范

  5. Swift:界面传值大全

    声明了代理属性之后,我们需要在处理界面跳转(返回)的方法中处理协议传值的逻辑了。

  6. Swift设计模式之保护代理模式

    转自Swift设计模式原文Design-Patterns-In-Swift

  7. MVVM 不是那么好

    我觉得MVVM是一种反人类的设计模式,它使架构更加混乱而非清晰。MVVM命名很糟糕名称是很重要的。ViewModel这一名称则没有发挥任何作用。ViewModel的第一种含义是modelfortheview。MVVM引进太多职责命名不够具体,导致这个类的任务无休止地增长。MVVM不改变你的架构viewmodel并不能从根本上改变你的应用程序的架构。我能想到的MVVM模式最大的好处就是它把“下水道”从苹果自带的viewcontrooller类转移到了viewmodel这一自定义的对象。

  8. swift设计模式学习 - 代理模式

    代理模式的组成抽象角色:通过接口或抽象类声明真实角色实现的业务方法。代理模式的基本实现上图是最基本的代理模式的结构图,下面将用Swift代码来实现一个基本代理模式:以上是一个最基本的代理模式的构成,这样可以用Proxy来代替RealSubject,从而对客户端隐藏真实的对象。高扩展性以上是我对于代理模式的理解,如果有不对的地方欢迎大家交流,最后谢谢大家的阅读~~

  9. swift3.0之UIImagePickerController的使用和注意事项

    在oc中使用UIImagePickerController只要设置好代理、写代理方法就行了,但是在swift中编译没有什么问题,但是运行的时候会报错,选择一张图片,会显示库是私有的,不能访问,遇到这样的问题很好的解决办法就是在info.plist文件中添加Privacy-PhotoLibraryUsageDescription和Privacy-CameraUsageDescription两个字符串

  10. KVC原理剖析

    协议定义KVC全称是KeyValueCoding,定义在NSkeyvalueCoding.h文件中,是一个非正式协议。基础操作KVC主要对三种类型进行操作,基础数据类型及常量、对象类型、集合类型。在使用KVC时,直接将属性名当做key,并设置value,即可对属性进行赋值。在KVC进行属性赋值时,内部会对基础数据类型做处理,不需要手动做NSNumber的转换。集合属性操作根据KVO的实现原理,是在运行时生成新的子类并重写其setter方法,在其内容发生改变时发送消息。

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部