天天看點

Java設計模式(6):擴充卡模式

擴充卡模式的定義

擴充卡模式把一個類的接口變換成用戶端所期待的另一種接口,進而使原本因接口不比對而無法在一起工作的兩個類能夠在一起工作。

擴充卡模式作為兩個不相容接口之間的橋梁。 這種類型的設計模式屬于結構模式,因為該模式組合了兩個獨立接口。

這種模式涉及一個單獨的類,它負責連接配接獨立或不相容接口的功能。

用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻隻有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不比對使得筆記本電腦無法使用。這時候一個三相到兩相的轉換器(擴充卡)就能解決此問題,而這正像是本模式所做的事情。

适配就是由“源”到“目标”的适配,而當中連結兩者的關系就是擴充卡。它負責把“源”過度到“目标”。

舉個簡單的例子,比如有一個“源”是一個對象人,他擁有2種技能分别是說日語和說英語,而某個崗位(目标)需要你同時回說日語、英語、和法語,好了,現在我們的任務就是要将人這個“源”适配的這個崗位中,如何适配呢?顯而易見地我們需要為人添加一個說法語的方法,這樣才能滿足目标的需要。

接着讨論如何加說法語這個方法,也許你會說,為什麼不直接在“源”中直接添加方法,我的了解是,适配是為了實作某種目的而為一個源類暫時性的加上某種方法,是以不能破壞原類的結構。同時不這麼做也符合Java的高内聚,低耦合的原理。既然不能直接加,接着我們就來說該怎麼來實作為人這個“源”添加一個方法,而又不破壞“源”的本身結構。

模式所涉及的角色有:

Java設計模式(6):擴充卡模式

1.目标(Target)角色:這就是所期待得到的接口。注意:由于這裡讨論的是類擴充卡模式,是以目标不可以是類。

2.源(Adapee)角色:現在需要适配的接口。

3.擴充卡(Adaper)角色:擴充卡類是本模式的核心。擴充卡把源接口轉換成目标接口。顯然,這一角色不可以是接口,而必須是具體類。

擴充卡模式有2種,第一種是“面向類的擴充卡模式”,第二種是“面向對象的擴充卡模式”。

類擴充卡模式

這類擴充卡模式就是主要用于,單一的為某個類而實作适配的這樣一種模式。

代碼實作:

//源:
 class Person {
        public void speakJapanese() {
            System.out.println("I can speak Japanese!");
        }

        public void speakEnglish() {
            System.out.println("I can speak English!");
        }
    }

//目标:
    interface Target {
        void speakJapanese();

        void speakEnglish();

        void speakFrench();
    }

//擴充卡:
    class Adapter extends Person implements Target {

        @Override
        public void speakFrench() {

        }
    }
           

為什麼稱其為類适配模式呢?很顯然的,Adapter類繼承了Person類,而在Java這種單繼承的語言中也就意味着,他不可能再去繼承其他的類了,這樣也就是這個擴充卡隻為Person這一個類服務。是以稱其為類适配模式。

對象擴充卡模式

對象擴充卡模式是把“源”作為一個對象聚合到擴充卡類中。

class Person {
        public void speakJapanese() {
            System.out.println("I can speak Japanese!");
        }

        public void speakEnglish() {
            System.out.println("I can speak English!");
        }
    }

    interface Target {
        void speakJapanese();

        void speakEnglish();

        void speakFrench();
    }

    class Adapter implements Target {

        Person mPerson;

        public Adapter(Person person) {
            this.mPerson = person;
        }

        @Override
        public void speakJapanese() {
			 mPerson.speakJapanese();
        }

        @Override
        public void speakEnglish() {
			 mPerson.speakEnglish();
        }

        @Override
        public void speakFrench() {

        }
    }
           

對象的擴充卡模式,把“源”作為一個構造參數傳入擴充卡,然後執行接口所要求的方法。這種适配模式可以為多個源進行适配。彌補了類适配模式的不足。

現在來對2種适配模式做個分析:

1.類的适配模式用于單一源的适配,由于它的源的單一話,代碼實作不用寫選擇邏輯,很清晰;而對象的适配模式則可用于多源的适配,彌補了類适配模式的不足,使得原本用類适配模式需要寫很多擴充卡的情況不複存在,弱點是,由于源的數目可以較多,是以具體的實作條件選擇分支比較多,不太清晰。

2.擴充卡模式主要用于幾種情況:(1)系統需要使用現有的類,但現有的類不完全符合需要。(2)講彼此沒有太大關聯的類引進來一起完成某項工作(指對象适配)。

接口擴充卡模式(預設适配模式)

這種模式的核心歸結如下:當你想實作一個接口但又不想實作所有接口方法,隻想去實作一部分方法時,就用中預設的擴充卡模式,他的方法是在接口和具體實作類中添加一個抽象類,而用抽象類去空實作目标接口的所有方法。而具體的實作類隻需要覆寫其需要完成的方法即可。代碼如下:

public interface Job {
	
	public abstract void speakJapanese();
	public abstract void speakEnglish();
	public abstract void speakFrench();
	public abstract void speakChinese();
	
}

public abstract class JobDefault implements Job{

	public void speakChinese() {
		
	}

	public void speakEnglish() {
		
	}

	public void speakFrench() {
		
	}

	public void speakJapanese() {
		
	}

}

public class JobImpl extends JobDefault{
	
	public void speakChinese(){
		System.out.println("I can speak Chinese!");
	}
	
}

           

擴充卡模式的優缺點

優點

  1. 更好的複用性:系統需要使用現有的類,而此類的接口不符合系統的需要。那麼通過擴充卡模式就可以讓這些功能得到更好的複用。
  2. 更好的擴充性:在實作擴充卡功能的時候,可以擴充自己源的行為(增加方法),進而自然地擴充系統的功能。
  3. 完美實作解耦,通過增加擴充卡類将适配者與目标接口聯系起來,無需修改原有實作;
  4. 符合開閉原則

缺點

會導緻系統紊亂:濫用擴充卡,會讓系統變得非常零亂。例如,明明看到調用的是A接口,其實内部被适配成了B接口的實作,一個系統如果太多出現這種情況,無異于一場災難。是以如果不是很有必要,可以不使用擴充卡,而是直接對系統進行重構。

繼續閱讀