设计模式 --> 代理模式(一)(高清多图,源码模拟)

    引言:Java 动态代理机制的出现,使得开发人员不用手工编写代理类,只要指定一组接口及委托类的对象,便能动态的获得代理类。代理类会负责将所有的方法调用分配到委托对象上反射执行,在分配指定过程中,开发人员还可以按需掉正委托类对象及其功能,是一套非常灵活有弹性的代理框架。
一、什么是代理模式
    为其他对象提供一种代理以控制对这个对象的访问。代理类负责为委托类预处理消息,过滤信息并转发消息,以及进行消息被委托执行后的后续处理。

    为了保持行为的一致性,委托类和代理类会实现相同的接口,所以,在访问者角度来看二者并无区别。通过代理类这中间一层,能有效控制对委托类的直接访问,也能很好的隐藏和保护委托类的对象,同时也为实施不同控制策略预留了空间,从而在设计上具有更大的灵活。

二、代理模式如何使用
1、在进行下一步之前,我们先来讨论一下 继承、聚合 孰优孰劣。
1.1 接口

1.2 委托类

1.3 继承委托类实现代码运行时间的计算

1.4 代理类

1.5 运行

当我们想去增加一个记录日志的功能时,通过继承,需要再写一个方法来继承超类。如果想要一个功能为先记录日志,后计算代码运行时间,或二者颠倒或再加入新的功能,我们会发现通过继承来实现的方式会变得十分庞大而且不利于维护。所以继承是最不推荐的方式,那么采用聚合的方式就会更好吗?举例如下:
代理类:记录时间

代理类:记录日志

运行

运行结果:

由此可以看出,通过聚合来实现的方式有很大的优势,而且使得代码的可扩展性也大大提高。

三、动态代理
    动态代理类的字节码在程序运行时,通过 Java 的反射机制动态生成,无需手工编写源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为 Java 的反射机制可以生成任意类型的动态代理类。 Java.lang.reflect 包中的 Proxy 类和 InvocationHandler 接口提供了动态生成代理类的能力。
代码如下:(动态代理机制)
1、定义接口 Moveable

2、定义委托类

3、模拟 Proxy 类(因为往后还有更深的改动,于是将方法名定义为:XXX1)
   Proxy 类的主要功能:
   -- 代理类生成的目的地
   -- 编译生成 .class 文件
   -- 加载到内存,生成新的对象
   -- 产生新的构造方法
------------------------------------------------------------------------------------
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Proxy {
	
	public static Object newProxyInstance1() throws Exception{
		String rt = "\r\n";
		
		String str = 
				"package com.inspur.simpleProxy;" + rt +

				"public class TankTimeProxy implements Moveable{" + rt +
			
				"	public TankTimeProxy(Moveable t){" + rt +
				"		this.t = t;" + rt +
				"	}" + rt +
			
				 "	Moveable t;" + rt +
				 "	@Override " + rt +
				 "	public void move()" + "{" + rt +
				 "      System.out.println(\"Start time\");" + rt +
				 "		long start = System.currentTimeMillis();" + rt +
				 "		t.move();" + rt + 
				 "		long end = System.currentTimeMillis();" + rt +
				 "		System.out.println(\"using time == \" + (end - start));" + rt +
				 "		System.out.println(\"End time\"); " + rt +
				 "	}" + rt +
				 "}";
		/*
		 * 要生成的目的地
		 */
		String fileName = System.getProperty("user.dir") + "/src/com/inspur/simpleProxy/TankTimeProxy.java";
		File file = new File(fileName);
		FileWriter fileWriter = new FileWriter(file);
		fileWriter.write(str);
		fileWriter.flush();
		fileWriter.close();
		
		/*
		 * 编译,生成 .class 文件
		 */
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		System.out.println(compiler.getClass().getName());
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
		Iterable iterable = fileManager.getJavaFileObjects(fileName);
		CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
		task.call();
		fileManager.close();
		
		/*
		 * load to memory , create an instance
		 * 加载到内存,生成新对象
		 */
		// 将硬盘上的 Java 文件,放到内存中的类中,需要指定路径
		// 此方式还可以从网上去 load 类,通过网络传来的类 , 也可以通过此方式来 load 类
		// user.dir 当前文件根目录
		
		URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
		URLClassLoader urlClassLoader = new URLClassLoader(urls);
		Class c = urlClassLoader.loadClass("com.inspur.simpleProxy.TankTimeProxy");
		System.out.println(c);

		// 拿到其中的构造方法,得到方法,通过参数来确定。  找一个构造方法,这个构造方法的参数类型是 Moveable ,便得到了 TankTimeProxy
		Constructor constructor = c.getConstructor(Moveable.class);
		//Object m = constructor.newInstance(new Tank());
		//m.move();
		// c.newInstance(); 会产生一个新的构造方法
		Moveable m = (Moveable) constructor.newInstance(new Tank());
		return m;
	}


------------------------------------------------------------------------------------
4、编写 Client 类来对 Proxy 的方法进行调用。

5、运行结果如下

-- 通过此例,我们可以发现,TankTimeProxy 类是自动生成的,意味着我们根本不需要知道代理类是什么,只需要去调用 Proxy.newProxyIm=nstance 即可,这样就大大减少了很多具体代理类的生成,这就是动态代理,.class 文件是我们动态生成的。

   这样做确实可以产生一个动态代理,但是,我们会发现,我们所生成的代理,只能代理 moveable 接口。那么,如何产生任意接口的呢?,请看 
   设计模式 --> 代理模式(二),将会有各种改进。
四、代理模式的作用
1、远程代理:为一个对象在不同地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。
2、虚拟代理:根据需要创建开销很大的的对象,通过它来存放实例化需要很长的时间真实对象。
3、安全代理:用来控制真实对象访问时的权限。
4、智能代理:当调用真实对象时,代理处理另外一些事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值