博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
代理模式
阅读量:6258 次
发布时间:2019-06-22

本文共 4424 字,大约阅读时间需要 14 分钟。

hot3.png

定义

在《Head First 设计模式》一书中设计模式的定义如下:

代理模式为另一个对象提供一个替身或者占位符以控制对这个对象的访问

这是什么意思呢,也就是使用代理模式创建了一个对象的代表对象,让代表对象控制对这个对象的访问,被代理的对象可以是远程对象,创建开销大的对象,或者需要基于权限控制对象的访问。

1. 代理的对象是远程对象,比如说,你需要调用一个对象下的一个方法,而该对象是跑在远程的服务器上的,也就是在另外一个  JVM上面,这样就可以使用代理模式来代理对远程对象的访问,

2. 创建开销大的对象,比如加载配置文件等。

3. 基于权限控制对象的访问,比如一个论坛来说,不同权限的人可以看到的板块不同,普通游客的权限就看不了VIP权限的板块等。

此外,代理对象可以在调用真实对象的方法之前,之后可以进行相应的处理。

类图

下面是它的类图

可以看到代理模式一般有三个角色,

顶层接口:定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;

真实主题:真正实现业务逻辑的类;

代理类:用来代理和封装真实主题;

例子

下面以网站上加载图片为例:

由于网络的原因,图片加载需要很长时间,而此时,在页面显示“图片正在加载中,请稍等...”,加载成功后,就显示图片:

首先定义顶层接口:

/** * 共同接口 * @author Administrator * */public interface Icon {	/**	 * 获取图片的宽度	 * @return	 */	int getWidth();		/**	 * 获取图片的高度	 * @return	 */	int getHeight();		/**	 * 加载图片	 */	void loadImage();}

代理对象:

/** * 代理对象,拥有真实对象的引用 *  * @author Administrator * */public class IconProxy implements Icon {	/**	 * 真实对象	 */	private ImageIcon imageIcon;	public IconProxy() {		imageIcon = new ImageIcon();	}	@Override	public int getWidth() {		System.out.println("正在获取宽度,请稍等...");		// 模拟真实对象的耗时操作		waitTime(3000);		if (imageIcon != null) {			int width = imageIcon.getWidth();			System.out.println("获取宽度成功,宽度为:" + width);			return width;		}		return 0;	}	@Override	public int getHeight() {				System.out.println("正在获取高度,请稍等...");		// 模拟真实对象的耗时操作		waitTime(3000);		if (imageIcon != null) {						int height = imageIcon.getHeight();						System.out.println("获取宽度成功,宽度为:" + height);						return height;		}		return 0;	}	@Override	public void loadImage() {				System.out.println("正在加载图片,请稍等...");		// 模拟真实对象的耗时操作		waitTime(3000);				if (imageIcon != null) 		{			imageIcon.loadImage();		}	}	void waitTime(long millis) {		try {			Thread.sleep(millis);		} catch (InterruptedException e) {			e.printStackTrace();		}	}}

真实对象:

/** * 真实对象 * @author Administrator * */public class ImageIcon implements Icon{	@Override	public int getWidth() {		// 复杂计算		return 1000;	}	@Override	public int getHeight() 	{		// 复杂计算		return 500;	}	@Override	public void loadImage() 	{		System.out.println("加载成功");	}}

测试:

public static void main(String[] args) {				Icon proxy = new IconProxy();				proxy.getWidth();				proxy.getHeight();				proxy.loadImage();			}

结果:

正在获取宽度,请稍等...获取宽度成功,宽度为:1000正在获取高度,请稍等...获取宽度成功,宽度为:500正在加载图片,请稍等...加载成功

上面这种方法,需要我们为每一个类写一个代理类,代理类是在运行之前就已经写好的,这种代理方式称之为静态代理,

而动态代理是代理类不需要我们编写,而是在运行的时候,动态生成的。

java的API中,可以使用 java.lang.reflect.InvocationHandler 类来实现动态代理。

下面用 java.lang.reflect.InvocationHandler 来改写上面的例子:

顶层接口还是不变:

/** * 共同接口 * @author Administrator * */public interface Icon {	/**	 * 获取图片的宽度	 * @return	 */	int getWidth();		/**	 * 获取图片的高度	 * @return	 */	int getHeight();		/**	 * 加载图片	 */	void loadImage();}

真实主题也不变:

/** * 真实对象 * @author Administrator * */public class ImageIcon implements Icon{	@Override	public int getWidth() {		// 复杂计算		return 1000;	}	@Override	public int getHeight() 	{		// 复杂计算		return 500;	}	@Override	public void loadImage() 	{		System.out.println("加载成功");	}}

之后,定一个类实现 java.lang.reflect.InvocationHandler 接口,该类是动态创建代理需要的。

public class IconInvocationHandler implements InvocationHandler {	private Icon icon;	public IconInvocationHandler(Icon icon) {		this.icon = icon;	}	@Override	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {		try {            return method.invoke(icon, args);        } catch (InvocationTargetException e){            throw e.getCause();        }	}}

之后就可以使用 java.lang.reflect.Proxy 来动态的创建我们的代理对象

Proxy.newProxyInstance(ClassLoader loader, Class
[] interfaces, InvocationHandler h)

测试:

public static void main(String[] args) {		Icon imageIcon = new ImageIcon();		InvocationHandler handler = new IconInvocationHandler(imageIcon);		Icon icon = (Icon) Proxy.newProxyInstance(imageIcon.getClass().getClassLoader(),				imageIcon.getClass().getInterfaces(), handler);		System.out.println("正在加载宽度,请稍等...");		waitTime(3000);		int width = icon.getWidth();		System.out.println("加载成功,宽度为:" + width);		System.out.println("正在加载高度,请稍等...");		waitTime(3000);		int height = icon.getHeight();		System.out.println("加载成功,高度为:" + height);				System.out.println("正在加载图片,请稍等...");		waitTime(3000);		icon.loadImage();	}	// 模拟耗时操作	static void waitTime(long millis) {		try {			Thread.sleep(millis);		} catch (InterruptedException e) {			e.printStackTrace();		}	}

结果:

正在加载宽度,请稍等...加载成功,宽度为:1000正在加载高度,请稍等...加载成功,高度为:500正在加载图片,请稍等...加载成功

相关模式

策略模式:

模板方法模式:

单例模式:

适配器模式:

装饰者模式:

观察者模式:

状态模式:

转载于:https://my.oschina.net/mengyuankan/blog/1610080

你可能感兴趣的文章
Java 字符串处理
查看>>
安装nginx服务实战
查看>>
Python基础语法
查看>>
Net Standard扩展支持实例分享
查看>>
Xen虚拟机安装
查看>>
Varnish配置应用
查看>>
zstack虚拟机找不到硬盘信息
查看>>
Outlook客户端和Exchange服务器连接问题排错常用工具——Office配置扫描
查看>>
登录信息提示
查看>>
EXCHANGE2003系列总结-7:OWA下修改密码
查看>>
Zabbix安装图解教程
查看>>
oracle数据类型
查看>>
MSSQL sum()计算expression转化为数据类型int时发生算术溢出错误解决
查看>>
oracle 11g rac 笔记(VMware 和esxi主机都可以使用)
查看>>
golang钉钉群机器人订阅自定义主题百度新闻
查看>>
Backend-as-a-Service (BaaS) for Efficient Software Development
查看>>
php的curl获取https加密协议请求返回json数据进行信息获取
查看>>
检查HP服务器硬盘状态脚本
查看>>
Java基础之函数
查看>>
NAT负载均衡_ftp
查看>>