擴充套件類的三種方式(繼承,裝飾模式,動態代理)

四月的螢火之光發表於2017-11-12

擴充套件類的三種方式(繼承,裝飾模式,動態代理)

 

一、說明

擴充套件類的三種方式:

【1】基於繼承--- 方法覆蓋

【2】使用裝飾模式包裝類,增強原有行為

【3】使用動態代理--- 基於位元組碼Class在記憶體中執行過程

二、基礎介面和類

(1)貓介面

interface ICat{
    public void run();
}

(2)普通貓類

//貓類,實現ICat介面【基礎類】
class Cat implements ICat{
    @Override
    public void run() {
       System.out.println("貓捉了一隻老鼠...");
    }
}

三、擴充套件的三種方式

1、基於繼承--- 方法覆蓋

(1)程式碼:

package proxy;
//1.繼承--匿名內部類測試
public class InheritMethod {

	public static void main(String[] args) {
		Cat cat=new Cat(){
			@Override
			public void run(){
				//加強的內容... 
				System.out.println("貓的奔跑的速度 為 25m/s...");
				super.run();
			}
		};
		cat.run();//呼叫加強後的方法

	}
}

(2)結果:

貓的奔跑的速度 為 25m/s...

貓捉了 一隻 老鼠...

2、使用裝飾模式包裝類,增強原有行為

(1)程式碼:

【1】裝飾類

package proxy;

//裝飾類【加強類】
//對被裝飾類的方法進行加強
//用的時候, 要滿足的條件:

/*裝飾設計模式 :   裝飾者 和 被裝飾者
*用的時候, 要滿足兩個條件:
*第一個:裝飾者和被裝飾者 必須要實現同樣的介面或者 有共同 父類 
*第二個:被裝飾者 必須要 傳遞給 裝飾者,即:裝飾者持有 對被裝飾者的引用
*/
public class DecratorCat implements ICat{
	private ICat cat;//被裝飾者
	public DecratorCat(ICat cat){
		this.cat=cat;
	}
	@Override
	public void run() {
		//新增加強的內容
		System.out.println("貓捉住了老鼠只用了3秒的時間");
		//呼叫 原有的方法
		cat.run();
	}
	
}

【2】加強測試類

package proxy;

//2.裝飾者設計模式測試
public class DecratorCatTest {
	public static void main(String[] args) {

		ICat cat=new Cat();//原來的貓
		DecratorCat decratorCat=new DecratorCat(cat);//被裝飾後的貓
		decratorCat.run();

	}

}

(2)結果:

貓捉住了老鼠只用了3秒的時間

貓捉了 一隻 老鼠...

 

3、使用動態代理--- 基於位元組碼Class在記憶體中執行過程

(1)程式碼:

package proxy;


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

import org.junit.Test;

public class MethodEnhancement {

	//3.動態代理
	//代理模式:給某一個物件提供一個代理,並由代理物件控制對原物件的引用。
	//這個代理可以對源物件的一些方法進行加強處理
	//Porxy類
	//代理物件的產生:static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
	@Test
	public void test3(){
		final ICat cat=new Cat();//要代理的貓物件【代理】
		//Object obj=Proxy.newProxyInstance(loader, interfaces, h)
		
		ClassLoader loader = MethodEnhancement.class.getClassLoader();
		Class<?>[] interfaces = cat.getClass().getInterfaces();
		//代理貓物件
		//loader:任意的類載入器都行
		//interfaces:要的是真是的要產生是哪個類的代理物件
		ICat proxyCat=(ICat)Proxy.newProxyInstance(loader, interfaces, new InvocationHandler(){

			/*解釋:本程式碼作用---呼叫了,代理物件的一個方法,其中:方法裡面的引數是什麼也在這裡說明了
			 * 
			 * @param proxy---代理物件
			 * @param method---呼叫的方法的物件(將呼叫方法當作一個method物件傳遞進來)
			 * @param args---將呼叫方法的時候,傳遞的引數封裝到一個Object[]中傳遞進來
			 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
			 */
			
			//當呼叫代理貓:ProxyCat的任何方法時,都會進入這裡執行相應的程式碼
			//這裡的相應程式碼指的是:Cat物件裡面的方法
			//言外之意:ProxyCat(代理貓)具備Cat(普通貓)的所有方法,但是代理貓可以在
			//原來的相應方法上做增強操作!或者不做任何操作--程式碼:method.invoke(cat, args)
			//不做任何操作,就是呼叫Cat物件的某個方法method,其中裡面的引數情況為Object[] args--》mehtod.invoke(cat,args)
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				
				//當呼叫了代理物件ProxyCat的run()方法時,執行此段程式碼
				if(method.getName().equals("run")){
					
					//結果:加強run方法+原有run方法
					
					//加強原來的run方法
					System.out.println("代理加強————————————————————————");
						System.out.println("這貓的奔跑速度果然是非常好啊");
					//呼叫原來的run方法
					return method.invoke(cat, args);//cat物件的原有的方法
				}
				else{
					System.out.println("方法名:"+method.getName());
					//當代理貓(ProxyCat)呼叫普通貓(Cat)的除了run方法以外的方法時,直接返回普通貓的該方法
					return method.invoke(cat, args);//cat物件的原有的方法
				}
				
//				//當代理貓(ProxyCat)呼叫普通貓(Cat)的除了run方法以外的方法時,直接返回普通貓的該方法
//				return method.invoke(cat, args);//cat物件的原有的方法
			}
			
		});
		//關鍵點:
		//當ProxyCat代理貓,呼叫了代理物件【代理物件:Cat】的任何的方法的時候, 都會 執行 invoke方法裡的邏輯 
		
		//ProxyCat代理貓
		proxyCat.run();//代理貓呼叫了run方法
		
		proxyCat.hashCode();//代理貓呼叫了hashCode方法
		proxyCat.toString();//代理貓呼叫了toString方法
		
	}
}

(2)結果:

代理加強————————————————————————

這貓的奔跑速度果然是非常好啊

貓捉了 一隻 老鼠...

方法名:hashCode

方法名:toString

 

 

四、三種方式說明

(1)基於繼承--- 方法覆蓋

         繼承父類方法,然後在父類的方法上進行擴充套件操作

(2)使用裝飾模式包裝類,增強原有行為

裝飾類【加強類】--對被裝飾類的方法進行加強

裝飾設計模式:裝飾者 和 被裝飾者

用的時候, 要滿足兩個條件:

第一個:裝飾者和被裝飾者 必須要實現同樣的介面或者有共同父類

第二個:被裝飾者必須要傳遞給裝飾者,即:裝飾者持有對被裝飾者的引用

(3)使用動態代理--- 基於位元組碼Class在記憶體中執行過程

【1】說明

代理模式:給某一個物件提供一個代理,並由代理物件控制對原物件的引用。

作用:這個代理可以對源物件的一些方法進行加強處理

【2】使用

Proxy類

代理物件的產生:

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

引數說明:

loader:任意的類載入器都行

interfaces:要的是真是的要產生是哪個類的代理物件

InvocationHandler:裡面覆蓋方法 public Object invoke(Objectproxy, Methodmethod, Object[]args)

 

代理方法的增強:(去裡面寫相關的程式碼即可)

publicObject invoke(Objectproxy, Methodmethod, Object[]args)

                  throws Throwable {

                     returnnull;

              }         

       });

 

比如:

ICat proxyCat=(ICat)Proxy.newProxyInstance(loader,interfaces,new InvocationHandler(){

@Override

*解釋:本程式碼作用---呼叫了,代理物件的一個方法,其中:方法裡面的引數是什麼也在這裡說明了

*@param proxy---代理物件

*@param method---呼叫的方法的物件(將呼叫方法當作一個method物件傳遞進來)

*@param args---將呼叫方法的時候,傳遞的引數封裝到一個Object[]中傳遞進來

publicObject invoke(Objectproxy, Methodmethod, Object[]args)

                  throws Throwable {

                     returnnull;

              }         

       });

相關文章