读书笔记_java设计模式深入研究 第七章 代理模式 Proxy

1,代理模式:一个类可以用作其他东西的接口,其他类可以通过此类去访问被代理者。

2,UML图如下:

3,角色:

ISubject:抽象主题接口,该接口定义对象和它的代理共用的接口。

RealSubject:真实主题角色,使实现抽象主题接口的类。

Proxy:代理角色,内部含有对真实对象的引用,从而可以操作真实对象,代理对象提供与真实对象相同的接口,以便在任何时候都可以替代真实对象。

4,简单代码:


package pattern.chp07.proxy;

 

/**

 *  类描述:抽象主题接口

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 24, 2014 3:51:12 PM   Jing   Created.

 *           

 */

public interface ITV {

	/**

	 * 

	 * 方法说明:购买电视

	 *

	 * Author:       Jing                

	 * Create Date:   Dec 24, 2014 3:51:35 PM

	 *

	 * @return void

	 */

	public void buyTV();

}

package pattern.chp07.proxy;

 

/**

 *  类描述:真实主题角色

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 24, 2014 3:53:25 PM   Jing   Created.

 *           

 */

public class Buyer implements ITV {

 

	public void buyTV() {

		

		System.out.println("TV");

	}

 

}

package pattern.chp07.proxy;

 

/**

 *  类描述:代理对象

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 24, 2014 3:54:04 PM   Jing   Created.

 *           

 */

public class BuyerProxy  implements ITV{

	

	private Buyer buyer;

	public void buyTV() {

		

		System.out.println("Proxy buy ...");

		buyer.buyTV();

	}

 

}

5,远程代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以在同一台主机中,也可在另一台主机中。

6,计数代理:简单例子,实现图书计数功能。


 

package pattern.chp07.proxy.book;

 

/**

 *  类描述:抽象主题

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 24, 2014 4:23:56 PM   Jing   Created.

 *           

 */

public interface IBorrow {

	/**

	 * 

	 * 方法说明:借阅

	 *

	 * Author:       Jing                

	 * Create Date:   Dec 24, 2014 4:24:18 PM

	 *

	 * @return

	 * @return boolean

	 */

	boolean borrow();

}

/**

 * 类描述:借阅实现类

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 25, 2014 9:41:09 AM Jing Created.

 * 

 */

public class Borrow implements IBorrow {

 

	private Book book;

 

	public Book getBook() {

		return book;

	}

 

	public void setBook(Book book) {

		this.book = book;

	}

 

	public boolean borrow() {

		

		//保存数据

		//some code 

		

		return true;

	}

 

}

 

package pattern.chp07.proxy.book;

 

import java.io.RandomAccessFile;

import java.util.Calendar;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

 

/**

 * 类描述:借书代理

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 25, 2014 9:43:32 AM Jing Created.

 * 

 */

public class BorrowProxy implements IBorrow {

 

	private Borrow obj;

 

	private Map<String, Integer> map;

 

	public BorrowProxy(Borrow obj) {

 

		this.obj = obj;

		map = new HashMap<String, Integer>();

	}

 

	public boolean borrow() {

 

		if (!obj.borrow()) {

 

			return false;

		}

 

		Book book = obj.getBook();

		Integer i = map.get(book.getNo());

		i = (i == null) ? 1 : i + 1;

		map.put(book.getNo(), i);

		return true;

	}

 

	/**

	 * 

	 * 方法说明:记录日志

	 * 

	 * Author: Jing Create Date: Dec 25, 2014 10:07:37 AM

	 * 

	 * @throws Exception

	 * @return void

	 */

	public void log() throws Exception {

 

		Set<String> set = map.keySet();

		String key = "";

		String result = "";

 

		Iterator<String> it = set.iterator();

		while (it.hasNext()) {

 

			key = it.next();

			result += key + "\t" + map.get(key) + "\r\n";

		}

		Calendar c = Calendar.getInstance();

		RandomAccessFile fa = new RandomAccessFile("c:/log.txt", "rw");

		fa.seek(fa.length());

		fa.writeBytes(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-"

				+ c.get(Calendar.DAY_OF_MONTH) + "\r\n");

		fa.writeBytes(result);

		fa.close();

	}

 

}

 

package pattern.chp07.proxy.book;

 

/**

 * 类描述:书籍实体类

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 24, 2014 4:21:57 PM Jing Created.

 * 

 */

public class Book {

	/**

	 * 书号

	 */

	private String no;

	/**

	 * 书名

	 */

	private String name;

 

	public Book(String no, String name) {

		super();

		this.no = no;

		this.name = name;

	}

 

package pattern.chp07.proxy.book;

 

/**

 *  类描述:

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 25, 2014 10:20:58 AM   Jing   Created.

 *           

 */

public class MainTest {

 

	public static void main(String[] args) throws Exception {

		Borrow br = new Borrow();

		BorrowProxy proxy = new BorrowProxy(br);

		Book book = new Book("1000", "cesf");

		br.setBook(book);

		

		proxy.borrow();//借阅

		

		book = new Book("1001", "sdadasd");

		br.setBook(book);

		proxy.borrow();

		

		proxy.log();

	}

}

?7,JDK动态代理

使用jdk动态代理实现对接收信件的计数。


package pattern.chp07.proxy.emailCount;

 

/**

 *  类描述:抽象主题

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 25, 2014 11:01:05 AM   Jing   Created.

 *           

 */

public interface IRegister {

	/**

	 * 

	 * 方法说明:等级来信

	 *

	 * Author:       Jing                

	 * Create Date:   Dec 25, 2014 11:01:44 AM

	 *

	 * @param msg

	 * @return void

	 */

	void regist(String msg);

}

package pattern.chp07.proxy.emailCount;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

 

/**

 * 类描述:创建代理类

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 25, 2014 11:09:45 AM Jing Created.

 * 

 */

public class GenericProxy {

 

	public static Object createProxy(Object obj, InvocationHandler invokeObj) {

 

		Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass()

				.getInterfaces(), invokeObj);

		return proxy;

	}

}

/**

 *  类描述:Email信件 

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 25, 2014 11:05:15 AM   Jing   Created.

 *           

 */

public class EmailFrom implements IRegister {

 

	public void regist(String msg) {

		

		System.out.println("From Email");

	}

 

}

package pattern.chp07.proxy.emailCount;

 

/**

 *  类描述:来自传统邮件

 * 

 *  @author:  Jing

 *  @version  $Id: Exp$ 

 *

 *  History:  Dec 25, 2014 11:06:03 AM   Jing   Created.

 *           

 */

public class PostFrom  implements IRegister{

 

	public void regist(String msg) {

		

		System.out.println("From Post!");

	}

 

}

 

/**

 * 类描述:计数器动态代理

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 25, 2014 11:07:22 AM Jing Created.

 * 

 */

public class CountInvoke implements InvocationHandler {

 

	private int count = 0;

	/**

	 * 主题对象

	 */

	private Object obj;

 

	public CountInvoke(Object obj) {

		this.obj = obj;

	}

 

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

 

		count++;

		method.invoke(obj, args);

		return null;

	}

 

	public int getCount() {

		return count;

	}

 

	public void setCount(int count) {

		this.count = count;

	}

 

}

public class Test {

 

	public static void main(String[] args) {

		

		IRegister email = new EmailFrom();

		IRegister post = new PostFrom();

		

		CountInvoke emailInvoke = new CountInvoke(email);

		CountInvoke postInvoke = new CountInvoke(post);

		

		IRegister emailproxy = (IRegister) GenericProxy.createProxy(email, emailInvoke);

		IRegister postproxy = (IRegister) GenericProxy.createProxy(email, postInvoke);

		

		emailproxy.regist("email");

		postproxy.regist("post");

		

		System.out.println(emailInvoke.getCount());

		

		postproxy.regist("post2");

		System.out.println(postInvoke.getCount());

	}

}

8,JDK源码:

-1,Proxy:

Proxy最主要的方法是Proxy.newProxyInstance方法,我们可以查看对应JDK
 API文档:

动态代理类是一个实现在创建类时,指定该类运行时的接口列表的类,该类具有如下行为。代理接口是代理类实现的一个接口。代理实例是代理类的一个实例。每个代理实例都有一个关联的调用处理程序对象,它可以实现InvocationHandler接口。通过其中一个代理接口的代理实例上的方法将被指派到实例的调用处理程序的invoke方法,并传递代理实例,识别调用方法的Method对象以及包含的参数。调用处理程序以适当的方法处理参数编码,并调用方法,将方法执行结果返回。

代理类具有以下属性:

代理类是公共的、最终的而不是抽象的。

未指定代理类的非限定名称,但是以字符串"$Proxy"开头的类名空间应该为代理类保留。

代理类扩展Proxy。

代理类会按一定顺序准确的实现其创建时的接口。

如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。

由于代理类实现了其在创建时指定的接口,所以对其Class对象调用getInterfaces将返回一个包好相同接口列表的数组,对齐Class对象调用getMethods方法将返回一个包含这些接口所有方法的Method对象数组,并且调用getMethod将会在代理接口中找到期望的一些方法。

如果Proxy.isProxyClass方法传递代理类,则该方法返回true。

每个代理类都有一个可以带一个参数(接口InvocationHandler)的公共构造方法,用于设置代理程序的调用处理程序。并非使用反射才能访问公共构造方法,通过Proxy.newInstance方法也可以返回代理实例。


newProxyInstance

 

public static Object newProxyInstance(ClassLoader loader,

                                      Class<?>[] interfaces,

                                      InvocationHandler h)

                               throws IllegalArgumentException

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于:

     Proxy.getProxyClass(loader, interfaces).

         getConstructor(new Class[] { InvocationHandler.class }).

         newInstance(new Object[] { handler });

 

Proxy.newProxyInstance 抛出 IllegalArgumentException,原因与 Proxy.getProxyClass 相同。

 

参数:

loader - 定义代理类的类加载器

interfaces - 代理类要实现的接口列表

h - 指派方法调用的调用处理程序

返回:

一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口

抛出:

IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制

NullPointerException - 如果 interfaces 数组参数或其任何元素为 null,或如果调用处理程序 h 为 null

-2,接口InvocationHandler

该接口是代理实例的调用处理程序实现的接口。

每个代理实例都有一个关联的调用处理程序,对代理实例调用方法的时,将方法进行编码并指派到它的调用处理程序的invoke方法。


invoke

 

Object invoke(Object proxy,

              Method method,

              Object[] args)

              throws Throwable

在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

参数:

proxy - 在其上调用方法的代理实例

method - 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。

返回:

从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出 NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出 ClassCastException。

抛出:

Throwable - 从代理实例上的方法调用抛出的异常。该异常的类型必须可以分配到在接口方法的 throws 子句中声明的任一异常类型或未经检查的异常类型 java.lang.RuntimeException 或 java.lang.Error。如果此方法抛出经过检查的异常,该异常不可分配到在接口方法的 throws 子句中声明的任一异常类型,代理实例的方法调用将抛出包含此方法曾抛出的异常的 UndeclaredThrowableException。

-3,使用代码:


/**

 * 类描述:动态代理实例

 * 

 * @author: Jing

 * @version $Id: Exp$

 * 

 * History: Dec 25, 2014 3:25:08 PM Jing Created.

 * 

 */

public class ProxyStudy {

	@SuppressWarnings("unchecked")

	public static void main(String[] args) throws Exception {

 

		Class<?> clazz = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);

		System.out.println("动态代理产生的类名为: " + clazz.getName());

 

		// 获取动态代理产生的类的构造方法

		Constructor<?>[] cons = clazz.getConstructors();

		for (Constructor<?> con : cons) {

 

			System.out.println("构造方法: " + con.getName() + "----对应参数: "

					+ Arrays.asList(con.getParameterTypes()));

		}

 

		// 获取动态类的普通方法

		Method[] methods = clazz.getDeclaredMethods();

		for (Method method : methods) {

 

			System.out.println("方法:" + method.getName() + "----对应参数: "

					+ Arrays.asList(method.getParameterTypes()));

		}

 

		// 构造方法需要InvocationHandler对象

		Constructor<?> constructor = clazz.getConstructor(InvocationHandler.class);

		Collection<Object> proxyBuildCollection = (Collection<Object>) constructor

				.newInstance(new InvocationHandler() {

					ArrayList<Object> target = new ArrayList<Object>();

 

					public Object invoke(Object proxy, Method method, Object[] args)

							throws Throwable {

						System.out.println("执行方法 : " + method.getName() + "前,参数为:"

								+ args.toString());

						Object result = method.invoke(target, args);

						System.out.println("执行方法 : " + method.getName() + "后。");

						return result;

					}

				});

		

		proxyBuildCollection.add("asd");

		proxyBuildCollection.add("asd");

		proxyBuildCollection.add("asd");

	}

}

9,JDK动态代理原理:

时间: 2024-10-29 19:11:27

读书笔记_java设计模式深入研究 第七章 代理模式 Proxy的相关文章

读书笔记_java设计模式深入研究 第六章 桥接模式

1,桥接模式:将抽象部分与实现部分分离,使他们可以独立变化.桥接模式可以实现的是不同方式的组合完成不同的功能,方式和功能完全分离,使得相互不影响. 2,UML模型: 3,简单代码实例: /** * * @(#) IPost.java * @Package pattern.chp06.bridge.simple * * Copyright ? JING Corporation. All rights reserved. * */ package pattern.chp06.bridge.simpl

读书笔记_java设计模式深入研究 第三章 工厂模式 Factory

1,简单工厂 -1,定制抽象接口. -2,定制具体子类. -3,定制工厂类,通过工厂类的静态方法返回不同的子类对象. package pattern.chp02.facroty; /**  *  类描述:汽车接口  *   *  @author:  Jing  *  @version  $Id: Exp$   *  *  History:  Dec 18, 2014 10:50:10 AM   Jing   Created.  *             */ public interface 

读书笔记_java设计模式深入研究 第五章 观察者模式 Observer

1,观察者模式适合解决多种对象跟踪一个对象数据变化的程序结构问题,一个称作"主题"的对象和若干个称作"观察者"的对象.在主题对象更新后会通知所有的观察者,使他们自动更新自己. 2,观察者UML类图: 3,角色解释: -1,抽象观察者(IObserver):为所有具体观察者定义接口,在得到主题通知的时候,更新观察者自身数据. -2,抽象主题(ISubject):使用数组引用维护一组观察者对象,可以增加和删除观察者,同时同志观察者自身的改变. -3,观察者(Observ

读书笔记_java设计模式深入研究 第二章 反射

1,JDK中反射类包含的内容: -1,Class类,代表一个类. -2,Constructor,代表类的构造方法. -3,Field,代表类成员 -4,Method,代表方法. 2,统一调用形式: 一个基本的使用反射的例子如下: package com.use; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class A 

读书笔记_java设计模式深入研究 第九章 访问者模式 Vistor

1,访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变.为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式,这就是访问者模式的动机. 2,UML图: 3,访问者角色: IElement:抽象的事物元素功能接口,定义了固定功能方法以及可变功能方法接口. Element:具体功能的实现类. IVisitor:访问者接口,为所有访问者对象声明一个visit方法,用来代表为对象结构添加的功能,原则上可

读书笔记_java设计模式深入研究 第十章 命令模式 Command

1,命令模式:主要针对需要执行的任务或用户提出的请求进行封装与抽象.抽象的命令接口描述了任务或请求的共同特征,而实现交由不同的具体命令对象完成.每个命令对象都是相互独立的,它负责完成需要执行的任务,却并不关心是谁调用的. 2,UML模型: 3,角色分析: -1,ICommander:抽象命令者,是一个接口,规定了用来封装请求的若干个方法. -2,ConcreteCommander:具体命令发送者,即命令源.实现命令接口. -3,Invoke:请求者,具体命令的管理和维护类.请求者是包含一个"命令

【读书笔记】C#高级编程 第七章 运算符和类型强制转换

(一)运算符 类别 运算符 算术运算符 + - * / % 逻辑运算符 & | ^ ~ && || ! 字符串连接运算符 + 增量和减量运算符 ++ -- 移位运算符 << >> 比较运算符 == != < > <= >= 赋值运算符 = += -= *= /= %= &= |= ^= <<= >>= 成员访问运算符(用于对象和结构) . 索引运算符(用于数组和索引器) [] 类型转换运算符 () 条件

大话设计模式第七章---代理模式模式PHP实现

<?php abstract class Subject { abstract public function request(); } class Real_subject extends Subject { public function request() { echo "真实请求"; } } class Proxy extends Subject { private $_real_subject = null; public function request() { if

大话设计模式C++实现-第7章-代理模式

一.UML图 二.概念 代理模式:为其他对象提供一种代理以控制对这个对象的访问. 三.应用场景 (1)远程代理,也就是为一个对象在不同的地址空间提供局部代表.这样可以隐藏一个对象存在于不同地址空间的事实. (2)虚拟代理,是根据需要创建开销很大的对象.通过他来存放实例化需要很长时间的真实对象.例如:图片加载的时候. (3)安全代理,用来控制真是对象访问时的权限. (4)智能指引,是指当调用真实的对象的时候,代理处理另外一些事. 根本原理:代理模式其实就是在访问对象的时候引入了一定程度的间接性,因