结构型模式之代理模式

静态代理:在使用静态代理时,被代理对象(目标对象)与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.

例子:明星与经纪人之间就是被代理和代理的关系,明星出演活动的时候,明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)
代码:
抽象主题:

public interface ISong{

	//公共抽象方法
	void Sing();
}

真实主题:

//目标对象
public class JJ implements ISong{

	@Override
	public void Sing() {
		System.out.println("林俊杰在唱歌....");
	}

}

代理主题:

//代理对象
public class JJProxy implements ISong{
	
	//持有目标对象的引用!
	private JJ jj;
	
	public JJProxy(JJ jj) {
		super();
		this.jj = jj;
	}

	@Override
	public void Sing() {
		System.out.println("林俊杰唱歌前的准备工作");
		jj.Sing();
		System.out.println("林俊杰唱歌后的收拾工作");
	}

}

客户端测试:

public class Client {

	public static void main(String[] args) {
		
		ISong iSong; //面向接口编程:依赖倒转原则
		iSong = new JJProxy(new JJ());
		iSong.Sing();
        
        /**
            控制台输出:
            林俊杰唱歌前的准备工作
            林俊杰在唱歌....
            林俊杰唱歌后的收拾工作
        */
	}
}

优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:  因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

动态代理方式可以解决上面的问题



一:代理模式目的:就是为了对某个对象的增强
增强对象的手段
1.继承:被增强对象不能变,增强内容不能变
2.装饰者模式:被增强对象可变,增强内容不可变
3.动态代理:被增强对象可变,增强内容可变
所有使用装饰者模式的地方,都可以使用代理模式!

二:概述
今天来学习一下代理模式,学习动态代理模式一般都是在框架中使用,如果不写框架,基本上使用不到,但为什么还要去学呢?目的是为了更好的理解框架内部的原理,strust1,struts2,spring中都有用到!

今天其实就是学习一下JDK中的动态代理(Proxy)
Object proxyObj = Proxy.newProxyInstance(ClassLoader loader,class[] interfaces,InvocationHandler h);

newProxyInstance的三个参数:
ClassLoader :把.class文件加载到内存,形成Class对象,怎么获取呢? Class对象里面有个getClassLoader(),所以先得到Class对象就行了
class[]:指定的接口数组
InvocationHandler :它是一个接口!里面只有一个invoke()方法,它的名字叫调用处理器,
                                  其实无论你调用代理对象的什么方法,它都是在调用InvocationHandler的invoke()方法!

这个代码的含义:
在运行时动态的创建一组指定接口的实现类对象!(创建对象)
也就是说proxyObj 就是一个实现了interfaces里面的所有接口的实现类,至于它到底是什么类型我们不知道,我们只知道他是指定接口的实现类,而且它不会有.class文件,因为它是在运行的时候创建的!

示例代码:

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

interface A{
	
	void a();
}


interface B{
	
	void b();
}


public class Client {

	public static void main(String[] args) {
		
		ClassLoader classLoader = Client.class.getClassLoader();
		//这个proxyObj代理对象,就是实现了A和B接口!
		Object proxyObj = Proxy.newProxyInstance(classLoader, new Class[]{A.class,B.class},new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("你好动态代理");
				return null;
			}
		});
		
		/**
		 * 	既然说proxyObj代理对象是实现了A,B两个接口
		 *       疑问一:那么我想知道实现类具体是什么类型的!
		 *       疑问二:那么应该可以使用A,B接口中的方法
		 */
		System.out.println(proxyObj.getClass().getSimpleName());//$Proxy0,不知道什么类型,也不用管
		System.out.println(proxyObj instanceof A); //true
		System.out.println(proxyObj instanceof B); //true
		
		//直接调用是Object类中的方法,所以我得强转一下,不管调用代理对象中的什么方法,都会去执行InvocationHandler中的invoke()方法!, 除了getClass();
		A a = (A)proxyObj;
		a.a();
		a.toString();
	}
}

invoke方法中的三个参数!
invoke(Object proxy, Method method, Object[] args)
proxy:表示代理对象
method:表示当前被调用方法的反射对象
args:表示当前被调用方法的参数

三:实例
目标对象:就是需要被增强的对象
代理对象:就是需要维护一个目标对象的引用,然后在目标对象上增强的对象
目标方法:增强的内容 
代理对象 = 目标对象 + 增强!

动态代理中的角色:抽象主题,真实主题,代理主题
抽象主题

public interface Waiter {

	void server();
}

真实主题

public class ManWaiter implements Waiter{

	@Override
	public void server() {
		System.out.println("服务中....");
	}

}

代理主题和测试代码!

public class Client {

	public static void main(String[] args) {
		Waiter waiter = new ManWaiter();//目标对象
		
		ClassLoader classLoader = Client.class.getClassLoader();
		Class[] interfaces = {Waiter.class};
		InvocationHandler h = new WaiterInvocationHandler(waiter);
		//代理对象:就是在目标对象的基础上进行增强了的对象!
		Object proxyObj = Proxy.newProxyInstance(classLoader, interfaces,h);
		//强转一下才能使用接口中的方法
		Waiter w = (Waiter)proxyObj;
		w.server();
	}
}


class WaiterInvocationHandler implements InvocationHandler{
	
	//维护一个目标对象的引用
	private Waiter waiter;

	public WaiterInvocationHandler(Waiter waiter) {
		super();
		this.waiter = waiter;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("你好");
		this.waiter.server();
		System.out.println("再见");
		return null;
	}
	
}


还有一个cglib代理:暂时不写
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章