设计模式原来如此-代理模式(Proxy Pattern)

时间:2021-11-11 22:34:31

代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下:为其他对象提供一种代理以控制对这个对象的访问。

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

代理模式一般涉及到的角色有

1.抽象角色:声明真实对象和代理对象的共同接口

2.代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装

3.真实角色:代理角色所代表的真实对象,是我们最终要引用的对象

代理模式的优点

1.职责清晰

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

2.高扩展性

具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

3.智能化

通过动态代理,能够智能的代理委托角色。

代理模式分为静态代理和动态代理。

下面用个小例子说明一下静态代理,本例是个登录网络游戏,并打怪的例子。玩过网络游戏的都知道,打怪是很枯燥并且很累的过程,所以玩家就可以找代理(也就是游戏代练)来完成。

抽象主题角色,IGamePlayer

package com.zhouyu.proxy;

public interface IGamePlayer
{
//登录游戏
public void login(String user,String password); //打怪
public void killBoss(); //升级
public void upgrade();
}

具体主题角色,GamePlayer

package com.zhouyu.proxy;

public class GamePlayer implements IGamePlayer
{
private String name = ""; public GamePlayer(String name)
{
this.name = name;
} @Override
public void login(String user, String password)
{
System.out.println("登录名为:" + this.name + "登录成功");
} @Override
public void killBoss()
{
System.out.println(this.name + "在打怪");
} @Override
public void upgrade()
{
System.out.println(this.name + "又升了一级");
}
}

Proxy代理主题角色,GamePlayerProxy

package com.zhouyu.proxy;

public class GamePlayerProxy implements IGamePlayer
{
private IGamePlayer player; public GamePlayerProxy(IGamePlayer player)
{
this.player = player;
} @Override
public void login(String user, String password)
{
this.player.login(user,password);
} @Override
public void killBoss()
{
this.player.killBoss();
} @Override
public void upgrade()
{
this.player.upgrade();
}
}

客户端调用

package com.zhouyu.proxy;

import java.util.Date;

public class Client
{
public static void main(String[] args)
{
IGamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = new GamePlayerProxy(player); System.out.println("开始游戏时间:" + new Date());
proxy.login("zhangsan","password");
proxy.killBoss();
proxy.upgrade();
System.out.println("结束游戏时间:" + new Date());
}
}

通过使用静态代理,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

动态代理

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法

public object invoke(Object obj,Methodmethod, Object[] args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容

protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作

在使用动态代理类时,我们必须实现InvocationHandler接口

动态代理步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2.创建被代理的类以及接口

3.通过Proxy的静态方法

newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h) 创建一个代理

4.通过代理调用方法

下面用个例子来完成动态代理,跟静态代理的例子一样,同样是网络游戏的例子,抽象主题角色IGamePlayer和具体主题角色GamePlayer,Proxy代理主题角色采用动态的。

package com.zhouyu.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date; public class GamePlayerIH implements InvocationHandler
{
private Object object; public GamePlayerIH(Object object)
{
this.object = object;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("开始游戏时间:" + new Date()); Object result = method.invoke(this.object,args);
if(method.getName().equals("login"))
{
System.out.println("有人登录我的帐号");
} System.out.println("结束游戏时间:" + new Date());
return result;
}
}

客户端调用

package com.zhouyu.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class Client
{
public static void main(String[] args)
{
IGamePlayer player = new GamePlayer("张三");
InvocationHandler in = new GamePlayerIH(player); ClassLoader classLoader = player.getClass().getClassLoader();
IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(classLoader,
new Class[]{IGamePlayer.class},in);
proxy.login("zhangsan","password");
proxy.killBoss();
proxy.upgrade();
}
}

设计模式原来如此-代理模式(Proxy Pattern)的更多相关文章

  1. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  2. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  3. c#设计模式之代理模式(Proxy Pattern)

    引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...

  4. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)【转】

    介绍 为其他对象提供一个代理以控制对这个对象的访问. 示例 有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对象的访问. MessageModel ...

  5. 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 设计模式 - 代理模式&lpar;proxy pattern&rpar; 未使用代理模式 具体解释

    代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...

  7. 代理模式&lpar;Proxy pattern&rpar;

    代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...

  8. 设计模式——代理模式&lpar;Proxy Pattern&rpar;

    代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...

  9. 13&period;代理模式&lpar;Proxy Pattern&rpar;

    using System; namespace Test { //抽象角色:声明真实对象和代理对象的共同接口. //代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象, //同时代理 ...

  10. 大熊君说说JS与设计模式之------代理模式Proxy

    一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一 ...

随机推荐

  1. 【java开发系列】—— JDK安装

    前言 作为一个java开发者,安装JDK是不可避免的,但是配置路径却总是记不住,百度也有很多参考例子.这里仅仅当做以后参考的笔记记录. 说到JDK,就不得不提JRE.他们到底是什么呢? 通常我们进行j ...

  2. webBrowser执行js的方法,并返回值,c&num;后台取值

    private void Form1_Load(object sender, EventArgs e) { webBrowser1.Navigate(Application.StartupPath + ...

  3. BZOJ 2245&colon; &lbrack;SDOI2011&rsqb;工作安排&lpar; 费用流 &rpar;

    费用流模板题..限制一下不同愤怒值的工作数就可以了. ------------------------------------------------------------------------- ...

  4. CentOs下Mongodb的下载与安装

    1.下载MongoDB(64位) http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.9.tgz tar zxvf mongodb-lin ...

  5. Gitlab的安装

    # GitLab Server 的搭建 参考 https://about.gitlab.com/installation ## 1. 准备工作 以Centos7为例,准备一台至少内存为4G的机器. # ...

  6. Oracle中连接与加号(&plus;)的使用

    1.左外连接(Left outer join/ left join) left join是以左表的记录为基础的,左表的记录将会全部表示出来,而右表只会显示符合搜索条件的记录.右表记录不足的地方均为NU ...

  7. 读取Properties文件以及中文乱码问题

    在java类中常见的读取Properties文件方式,是使用Properties.load(inputStream);的方式但是常常出现中文乱码问题,这就很尴尬了 public synchronize ...

  8. jquery 学习&lpar;三&rpar; - 遍历操作

    HTML代码 <p>1111</p> <p>1111</p> <p>1111</p> <p>1111</p&g ...

  9. uboot i2c 操作函数记录

    I2C 在 u-boot 上面,有直接操作 I2C 的函数 // drivers/i2c/i2c_core.c // 设置在哪个 I2C bus 上工作 276 int i2c_set_bus_num ...

  10. Linux目录结构及文件基本操作

    作业: 1.创建一个homework目录,在该目录下新建名为1.txt~10.txt的文件 2.删除1.txt~5.txt 代码: mkdir homework cd homework touch { ...