結構型模式之代理模式

靜態代理:在使用靜態代理時,被代理對象(目標對象)與代理對象需要一起實現相同的接口或者是繼承相同父類,因此要定義一個接口或抽象類.

例子:明星與經紀人之間就是被代理和代理的關係,明星出演活動的時候,明星就是一個目標對象,他只要負責活動中的節目,而其他瑣碎的事情就交給他的代理人(經紀人)
代碼:
抽象主題:

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代理:暫時不寫
 

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