文档章节

java设计模式-代理模式

Clarence_D
 Clarence_D
发布于 2017/05/15 16:11
字数 1932
阅读 35
收藏 1

代理模式定义

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

代理模式中的角色

  • 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这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

 

 

© 著作权归作者所有

共有 人打赏支持
Clarence_D
粉丝 9
博文 125
码字总数 100989
作品 0
天津
程序员

暂无文章

Snackbar源码分析

目录介绍 1.最简单创造方法 1.1 Snackbar作用 1.2 最简单的创建 1.3 Snackbar消失的几种方式 2.源码分析 2.1 Snackbar的make方法源码分析 2.2 对Snackbar属性进行设置 2.3 Snackbar的show显示...

潇湘剑雨
9分钟前
0
0
分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业数据存储

分布式作业系统 Elastic-Job-Lite 源码分析 —— 作业数据存储 摘要: 原创出处 http://www.iocoder.cn/Elastic-Job/job-storage/ 本文基于 Elastic-Job V2.1.5 版本分享 1. 概述 本文主要分享...

DemonsI
16分钟前
0
0
jmockit demo

1、@Mocked,标识一个指定的class的实例或被测对象的参数被Mock掉。 2、@Capturing,标识一个被Mock的对象,从该对象派生的子类也被Mock了。 3、@Injectable,标识只有一个指定的被测对象的内...

我的老腰啊
29分钟前
0
0
内容换行

用 <textarea>13611112222 这里想换行 13877779999</textarea><textarea>13611112222 13877779999</textarea>...

小黄狗
31分钟前
0
0
学习设计模式——单例模式

1. 认识单例模式 1. 定义:一个类中仅有一个实例,并提供一个访问它的全局访问点。 2. 结构:仅一个Singleton类,其中包含一个static类变量,而类变量的类型就是Singleton类,而且Singleton...

江左煤郎
38分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部