設計模式——介面卡模式和外觀模式
介面卡模式和外觀模式
本文將分別介紹介面卡模式和外觀模式。
1、介面卡模式
1.1、定義
介面卡模式 將一個類的介面,轉換成客戶期望的另一個介面。介面卡讓原本介面不相容的類可以合作無間。
介面卡模式的定義非常易懂,就是將一個介面轉換成另一個介面,這樣一來就實現了介面的相容。生活中我們有很多介面卡的案例,例如我們請人從香港代購一個手機回來,因為香港使用的插頭制式是英式插頭,和內地的插座是不相容的,那麼要讓手機能夠充上電,我們就需要一個轉換插頭,這樣英式插頭就能夠使用內地的插座了,在這裡轉換插頭就是一個介面卡。我們就通過一個案例來介紹一下介面卡模式如何使用。
1.2、介面卡模式案例
1.2.1、需求
假設我們想模擬讀卡器作為記憶體卡和膝上型電腦之間的介面卡,我們將記憶體卡插入讀卡器,然後將讀卡器插入膝上型電腦,這樣我們就能通過膝上型電腦訪問記憶體卡了。
1.2.2、介面卡模式實現
我們可以分析一下需求,需求希望我們能夠通過膝上型電腦來存取記憶體卡上的資料,正常情況下我們通過膝上型電腦只能存取筆記本上的資料,而無法存取記憶體卡上的資料,因此我們先定義兩個介面表示膝上型電腦資料的存取和記憶體卡資料的存取,它們分別包含讀取資料和儲存資料的方法。
/**記憶體卡資料*/
public interface MemoryCard {
public void readData ();
public void writeData();
}
/**膝上型電腦資料*/
public interface LaptopData {
public void readData();
public void writeData();
}
接下來我們可以實現記憶體卡介面,假設我們定義一個手機記憶體卡類:
public class MobilePhoneMemoryCard implements MemoryCard {
@Override
public void readData() {
System.out.println("從手機記憶體卡讀取資料" );
}
@Override
public void writeData() {
System.out.println("向手機記憶體卡寫資料");
}
}
需求中是希望我們通過膝上型電腦訪問記憶體卡上的資料,但是膝上型電腦只能訪問筆記本中的資料,因此我們需要一個介面卡:
/**膝上型電腦介面卡*/
//1、首先需要實現想要轉換成的介面,在這裡就是膝上型電腦的資料
public class LaptopAdapter implements LaptopData {
//2、取得適配物件的引用,在這裡就是記憶體卡
private MemoryCard memoryCard;
public LaptopAdapter(MemoryCard memoryCard) {
this.memoryCard = memoryCard;
}
@Override
public void readData() {
//3、在讀取資料的方法中,我們使用記憶體卡的讀取方法
memoryCard.readData();
}
@Override
public void writeData() {
memoryCard.writeData();
}
}
這個介面卡它實現的是膝上型電腦資料介面,因為膝上型電腦只能訪問筆記本的資料,但是它包含一個手機記憶體卡的引用,因此在讀取和儲存資料的方法中,它可以呼叫記憶體卡的讀取和儲存方法來完成操作,對於客戶來說,這都是透明的,客戶仍然認為他訪問的是膝上型電腦的資料。
接下來我們就可以使用一個測試類來測試一下介面卡了:
public class TestMain {
public static void main(String[] args) {
MemoryCard memoryCard = new MobilePhoneMemoryCard();
LaptopData adapter = new LaptopAdapter(memoryCard);
adapter.readData();
adapter.writeData();
}
}
執行結果為:
從手機記憶體卡讀取資料
向手機記憶體卡寫資料
可以看到我們能夠正確地從膝上型電腦中訪問記憶體卡的資料了。
介面卡的類圖如下(圖片摘自《Head First設計模式》):
客戶通過目標介面呼叫介面卡的方法對介面卡發出請求,介面卡使用被適配者介面把請求轉換成被適配者的一個或多個介面,客戶接收到呼叫的結果,但是並未察覺這一切是介面卡在起轉換作用,客戶和被適配者是解耦的。
2、外觀模式
2.1、定義
外觀模式 提供了一個統一的介面,用來訪問子系統中的一群介面。外觀模式定義了一個高層介面,讓子系統更容易使用。
外觀模式的定義也很好理解,在一段業務程式碼中,我們經常會呼叫很多的子系統的方法,隨著子系統的增多,那麼業務程式碼的複雜度會越來越高,而外觀模式它提供了一個高層介面,這個高層介面可以訪問所有子系統的程式碼,而我們業務程式碼只需要呼叫這個高層介面就可以了。
2.2、外觀模式案例
2.2.1、需求
假設我們想定義一個系統來模擬電腦的啟動和關閉過程,其中電腦的啟動包含CPU啟動、記憶體啟動和硬碟的啟動,而電腦的關閉包含硬碟關閉、記憶體關閉和CPU關閉。
2.2.2、外觀模式實現
根據需求因為電腦的啟動和關閉包含幾個子模組的啟動和關閉,我們首先需要定義幾個介面表示電腦的CPU、記憶體和硬碟。
/**CPU*/
public interface CPU {
public void on();
public void off();
}
/**記憶體*/
public interface Memory {
public void on();
public void off();
}
/**硬碟*/
public interface HardDisk {
public void on();
public void off();
}
這幾個介面都定義了開啟和關閉方法,接著我們來實現這幾個介面:
public class MyCPU implements CPU {
@Override
public void on() {
System.out.println("CPU啟動");
}
@Override
public void off() {
System.out.println("CPU停止");
}
}
public class MyMemory implements Memory {
@Override
public void on() {
System.out.println("記憶體啟動");
}
@Override
public void off() {
System.out.println("記憶體停止");
}
}
public class MyHardDisk implements HardDisk {
@Override
public void on() {
System.out.println("硬碟啟動");
}
@Override
public void off() {
System.out.println("硬碟停止");
}
}
在沒有接觸外觀模式之前,我們啟動計算機和關閉計算機的時候都需要在客戶程式碼中定義這幾個模組,然後分別呼叫這幾個模組的開啟和關閉方法,這樣會讓客戶程式碼難以維護,比如如果我們要新增一個顯示器模組,那麼就需要修改客戶程式碼,這樣頻繁修改客戶程式碼顯然不是我們想要的。
有了外觀模式之後,根據外觀模式的定義,我們可以抽象出一個高層介面,由這個高層介面維護所有子系統的訪問,例如我們定義一個外觀類:
public class ComputerFacade {
CPU cpu;
Memory memory;
HardDisk hardDisk;
public ComputerFacade(CPU cpu, Memory memory, HardDisk hardDisk) {
this.cpu = cpu;
this.memory = memory;
this.hardDisk = hardDisk;
}
public void on() {
cpu.on();
memory.on();
hardDisk.on();
}
public void off() {
hardDisk.off();
memory.off();
cpu.off();
}
}
在這個外觀類中,我們聲明瞭電腦的幾個模組,並在開啟和關閉方法中呼叫對應模組的方法,以後需要新增和減少模組的時候只需要修改外觀類即可,無需修改客戶程式碼,客戶程式碼和複雜子系統之間實現瞭解耦。
我們可以定義一個客戶類來測試一下功能:
public class TestMain {
public static void main(String[] args) {
CPU cpu = new MyCPU();
Memory memory = new MyMemory();
HardDisk hardDisk = new MyHardDisk();
ComputerFacade computer = new ComputerFacade(cpu, memory, hardDisk);
computer.on();
System.out.println("oooooooooooooo");
computer.off();
}
}
執行結果如下:
CPU啟動
記憶體啟動
硬碟啟動
oooooooooooooo
硬碟停止
記憶體停止
CPU停止
3、總結
本文中介紹的介面卡模式和外觀模式都很好理解,案例也不難,使用時有以下幾個注意點:
- 當需要使用一個現有的類而其介面並符合需求時,可以使用介面卡,介面卡改變介面以符合客戶的期望;
- 當需要簡化並統一一個很大的介面或者一群複雜的介面時,可以使用外觀模式,外觀模式將客戶從一個複雜的子系統中解耦,要實現一個外觀,只需要將子系統組合進外觀中,然後將工作委託給子系統執行;
- 介面卡是將一個物件包裝起來以改變其介面,而外觀則是將一群物件包裝起來以簡化其介面。