文档章节

java设计模式-代理模式

走世界
 走世界
发布于 2017/09/06 01:23
字数 1932
阅读 13
收藏 0
点赞 0
评论 0

代理模式定义

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

代理模式中的角色

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

静态代理模式

实现个简单版本看看效果

    在上学那时候比较着迷于LOL这款游戏,这个游戏里的新英雄都是6300金币才可以购买,但一局游戏大约在20~30分钟获得100金币。想买一个英雄需要在这个游戏上花大把的时间来对战。游戏时间过长了腰酸背痛、眼睛干涩、手脚酸麻等,网络成瘾综合症就出来了。那怎么办?我想玩游戏,但又不想过长接触电脑的烦恼,我该如何解决?有办法,现在游戏代练的公司非常多,我只要把帐号交给他们,让他们来帮我对战获取金币,我只管享受我想玩那个英雄就可以玩那个英雄的乐趣就可以。

代码清单:定义游戏者接口

public interface ILOL {
    //登录
    public void login(String user,String password);
    //选择人机对战
    public void battle();
    //获取金币
    public void gold();
}

代码清单:游戏者实现类

public class LOL implements ILOL{

    private static String name = null;

    public LOL(String name){
        this.name = name;
    }
    @Override
    public void login(String user,String password) {
        System.out.println("登录名为"+user+"的用户"+this.name+"登录成功");
    }
    @Override
    public void battle() {
        System.out.println("选择了人机模式,开始进行对战");
    }
    @Override
    public void gold() {
        System.out.println("获得100游戏币");
    }
}

代码清单:游戏者正常操作

public class Test {
    public static void main(String[] args) {
        LOL user = new LOL("张三");
        //登录
        user.login("zhangsan","123456");
        System.out.println("开始时间"+new Date());
        //开始人机对战
        user.battle();
        //获得金币
        user.gold();
        System.out.println("结束时间"+new Date());
    }
}

来看下运行结果。

登录名为zhangsan的用户张三登录成功
开始时间Fri May 12 17:58:28 CST 2017
选择了人机模式,开始进行对战
获得100游戏币
结束时间Fri May 12 17:58:28 CST 2017

代码清单:定义代理接口

public class GameLOL implements ILOL{
    private  ILOL iLOL;
    public GameLOL(ILOL ilol){
        this.iLOL=ilol;
    }
    //代练登录
    public void login(String user, String password) {
        iLOL.login(user,password);
    }
    //代练人机对战
    public void battle() {
        iLOL.battle();
    }
    //代练获取金币
    public void gold() {
        iLOL.gold();
    }
}

代码清单:调用游戏代理

public class Test {
    public static void main(String[] args) {
        //我的账户
        ILOL user = new LOL("张三");
        //确定代练
        GameLOL gameLOL = new GameLOL(user);
        //代练登录
        gameLOL.login("zhangsan","123456");
        System.out.println("开始时间"+new Date());
        //代练开始人机对战
        gameLOL.battle();
        //代练替我获得金币
        gameLOL.gold();
        System.out.println("结束时间"+new Date());
    }
}

让游戏代理帮你练号的结果

登录名为zhangsan的用户张三登录成功
开始时间Fri May 12 18:00:08 CST 2017
选择了人机模式,开始进行对战
获得100游戏币
结束时间Fri May 12 18:00:08 CST 2017

动态代理模式

    咱们自己去实现的代理模式都属于静态代理模式。动态代理是在实现阶段不用关心代理谁,而是在运行阶段才指定代理那个对象。现在有一个比较流行的名称叫做面向切面编程AOP,其核心就是采用了动态代理模式,既然这么重要。我们来看看它是如何实现的。

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

代码清单:定义一个动态代理类

public class GameProxyH implements InvocationHandler {
    private Object obj = null;
    public GameProxyH(Object _obj){
        this.obj = _obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(obj, args);
        return invoke;
    }
}

代码清单:调用动态代理类

public class Test {
    public static void main(String[] args) {
        //代理的真实对象
        ILOL user = new LOL("张三");
        //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        GameProxyH gameProxyH = new GameProxyH(user);
        //我们这里使用gameProxyH这个类的ClassLoader对象来加载我们的代理对象
        ClassLoader cl = gameProxyH.getClass().getClassLoader();
        //动态生成一个代理类
        ILOL instance = (ILOL)Proxy.newProxyInstance(cl, user.getClass().getInterfaces(), gameProxyH);
        //登陆
        instance.login("zhangsan","password");
        System.out.println("开始时间"+new Date());
        //代练开始人机对战
        instance.battle();
        //代练替我获得金币
        instance.gold();
        System.out.println("结束时间"+new Date());
    }
}

来看下控制台的输出

登录名为zhangsan的用户张三登录成功
开始时间Mon May 15 15:55:20 CST 2017
选择了人机模式,开始进行对战
获得100游戏币
结束时间Mon May 15 15:55:20 CST 2017

代理模式优缺点

优点

  • 职责清晰:真是的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期代理完成一件事务,附带的结果就是编程简洁清晰。
  • 高扩展性:具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
  • 智能化:这在我们以上的讲解中还没有提现出来,不过在我们以下的动态代理章节中你就会看到代理的智能化有兴趣的读者也可以看看Struts是如何把表单元素映射到对象上的。

缺点   

  • 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

  • 增加了系统的复杂度。

代理模式使用场景

    在我看到网上介绍代理模式的代码時,给我的第一感觉就是为什么要用代理。咱们是想一下现实生活中,为什么打官司要请律师,就是因为你不想参与事件中的争吵。你只要跟律师交代清楚你的真是情况就可以。其他的事情如事前的调查,事后的在追查都交由律师去妥善处理。你再管在家里听消息就好了。

ps

    AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

 

 

© 著作权归作者所有

共有 人打赏支持
走世界
粉丝 3
博文 96
码字总数 91434
作品 0
和平
程序员

暂无文章

Win10专业版安装GIT后使用Git Bash闪退解决办法

百度后把过程和最终解决办法记录下来: 百度首先出来的解决办法如下: 来自:https://segmentfault.com/q/1010000012722511?sort=created 重启电脑 重新安装 安装到C盘 尝试网上的教程 \Git...

特拉仔
13分钟前
0
0
设计模式

1.装饰器模式 概念 允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰者可以在所委托被装饰者的行为之前或之后加上自己的行为,以达到特定的目的。 实现 增加一个修饰类包裹原来的...

EasyProgramming
28分钟前
1
0
用python2和opencv进行人脸识别

一、安装cv2 sudo apt-get install python-opencv opencv-data 二、 Haar特征分类器 Haar特征分类器就是一个XML文件,该文件中会描述人体各个部位的Haar特征值。包括人脸、眼睛、嘴唇等等。 ...

wangxuwei
28分钟前
0
0
python模板中循环字典

{% for k,v in user.items %} {{ k}} {{ v}} {% endfor %}

南桥北木
56分钟前
0
0
Java8系列之重新认识HashMap

简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap,类继承关系如下图所示: 下面针对各个实现类...

HOT_POT
今天
0
0
获取调用方的className

/** * 获取调用方的class * @return */private static String getInvoke() { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); S......

iborder
今天
0
0
深入了解一下Redis的内存模型!

一前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可或缺的一部分。 我们使用Redis时,会接触Redis的5种对象类型(字符...

Java填坑之路
今天
1
0
从实践出发:微服务布道师告诉你Spring Cloud与Spring Boot他如何选择

背景 随着公司业务量的飞速发展,平台面临的挑战已经远远大于业务,需求量不断增加,技术人员数量增加,面临的复杂度也大大增加。在这个背景下,平台的技术架构也完成了从传统的单体应用到微...

老道士
今天
1
0
大数据学习的各个阶段

第一阶段:Linux课程讲解Linux基础操作,讲的是在命令行下进行文件系统的操作,这是Hadoop学习的基础,后面的所有视频都是基于linux操作的。鉴于很多学员没有linux基础,特增加该内容,保证零linux...

董黎明
今天
0
0
CVE-2013-0077 堆溢出分析

找了很久才发现这个环境比较容易搭建分析... 环境: 系统---Win XP SP3 漏洞程序:QQPlayer 3.7.892.400 出错DLL:quartz.dll 6.5.2600.5512 调试工具:x32db+gflag.exe 过程: 首先gflag设置...

Explorer0
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部