设计模式学习笔记3-代理模式.md

1 设计模式学习笔记3-代理模式

代理的作用就是让我们关注自己的正事,其他的事情由代理商来帮我们办。

举个栗子:我们要去买火车票,但是一般买火车票都需要去火车站去购买,这样大大加大了我们购票的难度,也给我们增加了很多的负担,所以这时就有代理这个概念出现了,就是我们买火车票不需要去车站了而是找一个就近的代理商,在代理商这里直接购买火车票,其余的杂事(如怎么去火车站,排队等)都交给代理来帮我们完成,这就大大简化了我们的购票难度。

代理模式uml

代理模式

1.1 静态代理的实现

接口类:需要干什么

public interface HandleInterface {
	public void handle(String doSomething);
}

实际处理类:要干什么(买票)

/**
 * 静态代理之实际处理类
 * @author hong
 *
 */
public class Handle implements HandleInterface {
	public void handle(String doSomething) {
		System.out.println("我正在"+doSomething);
	}
}

静态代理类:通过代理来干一些列其他事情(代理商)

/**
 * Handle的静态代理类
 * @author hong
 *
 */
public class HandleProxy implements HandleInterface {
	Handle handle = new Handle();
	
	/**
	 * 在HandleProxy的handle方法中调用Handle的方法并在之前和之后干一些事情
	 */
	public void handle(String doSomething) {
		
		beforeHandleMethod();
		
		// 调用需要代理类的方法
		handle.handle(doSomething);
		
		afterHandleMethod();
		
	}
	
	public void beforeHandleMethod() {
		System.out.println("在方法【前】干了一系列事情。。。");
	}
	
	public void afterHandleMethod() {
		System.out.println("在方法【后】干了一系列事情。。。");
	}

}

测试类:测试静态代理

public class StaticProxyTest {
	public static void main(String[] args) {
		String doSomething = "吃饭";
		
		// 直接调用代理类的方法
		new HandleProxy().handle(doSomething);
		
	}
}

测试类输出

在方法【前】干了一系列事情。。。
我正在吃饭
在方法【后】干了一系列事情。。。

静态代理的优缺点:

静态代理的优点:代理类在调动预先需要的工作之前或之后帮我们干了一些事情(让我可以专注一件事)。

静态代理的缺点:当我们更改业务,比如不买票,而是买水等等,那么我们每一项业务都需要增加新的代理类,这样大大的增大了程序的负担,也是我们不想看见的(这时我们就需要使用动态代理类)。

1.2 动态代理的实现

动态代理主要是使用InvocationHandler接口和Proxy类来实现动态代理。

InvocationHandler需要实现的方法:

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

proxy:代表我们所代理的对象
method:代表需要调用对象的哪个方法
args:调用method需要用到的参数

Proxy需要使用的方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

loader:类加载器,定义了使用哪个类加载器来来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

接口:(定义要干什么)

public interface HandleInterface {
	public void doSomething(String something);
}

实际业务类:(干什么活)

/**
 * 动态代理之处理类
 * @author hong
 *
 */
public class Handle implements HandleInterface {

	@Override
	public void doSomething(String something) {
		System.out.println("我正在"+something);
	}

}

动态代理类:(在实际业务之前或之后干一些其他事情)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理类
 * @author hong
 *
 */
public class DynamicProxy implements InvocationHandler {
	
	// 需要代理的对象
	private Object proxyObject;
	
	public DynamicProxy(Object proxyObject) {
		this.proxyObject = proxyObject;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		beforeHandleMethod();
		
		method.invoke(proxyObject, args);
		
		afterHandleMethod();
		
		return null;
	}
	
	public void beforeHandleMethod() {
		System.out.println("在方法【前】干了一系列事情。。。");
	}
	
	public void afterHandleMethod() {
		System.out.println("在方法【后】干了一系列事情。。。");
	}

}

动态代理测试类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
	
	public static void main(String[] args) {
		HandleInterface realSubject = new Handle();
		
		InvocationHandler handler = new DynamicProxy(realSubject);
		
		HandleInterface handleProxy = (HandleInterface)Proxy.newProxyInstance(
				handler.getClass().getClassLoader(), 
				realSubject.getClass().getInterfaces(), 
				handler);
		handleProxy.doSomething("吃饭");
	}
}

输出结果

在方法【前】干了一系列事情。。。
我正在吃饭
在方法【后】干了一系列事情。。。

不惑解答

写完这些你可能就要问了,这动态代理和静态代理的想要的结果都一样,那为什么我们要使用动态代理而不用静态代理呢?(明明动态代理写起来更麻烦)。在这里我来说明一下,在业务少的时候我们使用静态代理其实比使用动态代理更快,但是当我们业务量大的时候,就如我在静态代理的缺点分析中说到的一样,我们使用静态代理需要创建大量的代理类(增加了jvm类加载的负担,使系统更加臃肿),这时我们就使用动态代理(当然业务类需要实现相应的接口),动态代理就是根据业务类实现的接口,让代理类实现了相应的接口,在运行时采用反射技术动态生成一个代理对象(减少我们写代理类的负担),在调用方法的业务方法的时候只需要进行一个强制的转换,就好了。

HandleInterface handleProxy = (HandleInterface)Proxy.newProxyInstance(
				handler.getClass().getClassLoader(), 
				realSubject.getClass().getInterfaces(), 
				handler);

动态代理的优缺点分析

优点:相对于静态代理不用写很多的代理类,代理类都是在运行时jvm通过反射动态生成的,只需让业务类实现相应的接口,在使用的时候进行强制转化,调用代理类的业务方法,就可达到目的。

缺点:写起来相对的复杂。

1.3 代理模式的应用场景

在服务器中存放了一个很大的图片,这时如果用户直接访问包含这个图片的网页,则会出现网页出来了,图片等很久都没出来的情况,这时我们就可以使用代理模式,即在后台对图片进行一系列的处理(减少图片的像素),把处理过的图片用来代替原图片,这样就可以加快网页的显示。

猜你喜欢

转载自blog.csdn.net/ZHLittleRed/article/details/82774287
今日推荐