表象模式(Facade Pattern)

表象模式(Facade Pattern)

我們知道,轉接器模式是透過介面的包裝,讓兩個素不相往來的物件開始友好的一個模式!

最棒的是,這種介面的使用上,他不用修改舊物件的程式碼就可以達到這樣的效益。

其實「表象模式」是另一個,透過改變介面的模式!只是,表象模式想這麼做的理由,是為了要簡化介面。

 

接著來說說今天的故事。

我愛唱KTV!!

這是真的,平常去好樂x,錢x都唱很久,唱到喉嚨都啞了

不過這次我們準備在家歡唱

不像是好樂x,在我們唱 KTV之前必須做一些準備。

一步一步來吧,唱歌總要有零嘴。所以…

1.打開炸薯條機

2.開始炸薯條

接著是環境的設定

3.放下營幕

4.打開投影機

5.將擴大機打開並調成AUX模式

6.打開音響後級

7.切換投影機成卡拉ok模式

8.打開卡拉OK機

9.切換卡拉OK機成伴唱模式

10.設定麥克風音量為4

11.設定…

2x.開始唱歌

天啊;在家唱KTV就是這麼麻煩,要設定這麼多的開關。

寫成程式來控制的話就像以下:

   1: 炸薯條機.On();
   2: 炸薯條機.Run();
   3:  
   4: 營幕.Down();
   5:  
   6: 投影機.On();
   7: 投影機.SetInput(擴大機);
   8:  
   9: 擴大機.On();
  10: 擴大機.SetInput(Aux);
  11:  
  12: 音響後級.On();
  13:  
  14: 卡拉OK機.On();
  15: 卡拉OK機.SetSong(11234);
  16: 卡拉OK機.SetNoVoiceMode();
  17: 卡拉OK機.SetMicVolume(4);
  18:  
  19: 卡拉OK機.Play();    //終於可以開始唱了

 

上述程式,共牽扯到6個類別,我們一步一步的做完(甚至還有省略一些步驟)。最後終於設定好歌曲、麥克風,可以歡唱了。

3個小時過後…

歡唱完,我們要將一切設備都關掉,怎麼辦呢?反向地將這一切的動作都再進行一次嗎?

未來假如要看dvd的話,或是只是要聽CD,是不是也是這麼的麻煩。

假如未來這套KTV劇院系統升級了,還必須重新設計稍稍不同的流程。

 

因此當我們自己在家唱ktv,顯然就是要執行這麼的複雜流程。

假如有一套「智慧」系統,自動地幫我們做掉這些呢?

噹噹~~

有一個表象模式你就可以解決這些繁複的流程。

表象模式可以將一個複雜的次系統,變的更加的友善 。

怎麼做呢?

現在我們就為卡拉ok劇院建立一個表象

image

於是我們建立了一個Home Movie Keraok表象的新類別,僅對外揭露幾個簡單的方法。例如,唱卡拉ok

回頭看看

這個表象類別,將整個卡拉ok系統的諸多元件,視為一個次系統,但是表象模式並非封裝了次系統。

表象提供了簡化的介面操作這些類別,所以客戶那一端如果覺得有必要,依然可以直接使用次系統的類別。

表象模式可以將客戶的程式碼從次系統中鬆綁。例如當初假如是透過表象模式來操作這個卡拉ok,那未來若要從金x換到點將x公司的卡拉ok

或是升級了音響設備,都不須改變客戶的程式碼,而只須改動表象的程式碼。

這樣看起來

轉接器模式與表象模式看起來做的方向一樣,但是這兩個模式的差異在於他們的目的仍是不同。

轉接器模式的目的是改變介面來符合客戶的期望,也就是要介面轉成不同的介面(客戶要的),然而表象模式的目的是提供次系統一個簡化的介面。

   1: public class HomeKeraokTheaterFacade
   2: {
   3:   Amplifier amp;
   4:   DVDPlayer dvd;
   5:   CDPlayer cd;
   6:   Projector projector;
   7:   Screen screen;
   8:   Light light;
   9:   Keraok keraok;
  10:   
  11:   //建構式
  12:   public HomeKeraokTheaterFacade(Amplifier amp, DVDPlayer dvd , CDPlayer cd , Projector projector , Screen screen , Light light , Keraok keraok)
  13:     {
  14:                 this.amp = amp;
  15:              this.dvd= dvd;
  16:              this.cd = cd ;
  17:              this.projector= projector;
  18:              this.screen= screen;
  19:              this.light= light;
  20:              this.keraok= keraok;
  21:     }
  22:                 
  23:     //開啟卡拉ok
  24:     public void TurnOnKeraok(){
  25:         amp.on;
  26:         screen.down();
  27:         projector.on();
  28:         light.off();
  29:         keraok.on();
  30:         keraok.setMicVolume(4);//設定音量
  31:         keraok.setNoVoice();  //設定伴唱模式
  32:     }
  33:     
  34:     //點歌
  35:     public void SelectSong(string SongID){
  36:         keraok.SetSong(SongID);
  37:     }
  38:     
  39:     //關閉卡拉ok系統
  40:     public void TurnOffKeraok(){
  41:         amp.off;
  42:         screen.up();
  43:         projector.off();
  44:         light.on();
  45:         keraok.off();
  46:     }
  47: }

因為我們之後在家唱卡拉ok也可以用輕鬆的方式來實踐了!

HomeKeraokTheaterFacade.TurnOnKeraok();

表象模式將多個類別所造成的一切複雜的真象,隱藏在背後,只顯露出一個美好的介面。

我們定義一下表象模式吧:(以下來自於Head First Design Pattern)

表象模式:提供了一個統一的介面,用來存取次系統中的一群介面。表象定義了一個較高層次的介面,讓次系統更容易使用。

然後 OO守則又多了一條:極小化守則(Least Knowledge),又可叫(Law of Demeter)

極小化守則是說,我們將來在設計系統的時候,不要將一堆類別綑綁在一起,我們要注意類別之間的互動。如果許多類別互相依賴

那就容易是一個易碎的系統。一當需求變動的時候,修改系統的一小部分都會影響到其他的部分。

這個守則另外還告訴我們,若以一個物件而言,此物件的方法定義內, 只應該引用物件的某些方法 這些方法必須屬於:

1.物件本身

2.被當作方法的參數而傳遞進來的物件

3.此方法所建立或實體化的任何物件

4.物件的任何元件。

也就是說,希望我們類別之間要保持朋友圈子為最小的狀態。

例如

   1: public int GetSpeed
   2: {
   3:     //不採用這個守則
   4:     Speeder speeder = car.getSpeeder();    //取得時速表
   5:     return speeder.getSpeed();            //透過時速表取得時速
   6: }
   7:  
   8: public int GetSpeed
   9: {
  10:     //採用這個守則
  11:         //我們在車子類別加入一個方法,來取得時速
  12:         //這樣就可以減少所依賴的類別數量
  13:          return car.getSpeed();    
  14: }

最後我們回顧一下,表象模式,未來你也可以透過表象模式幫客戶管理自己次系統中的全部元件了

image