1. 程式人生 > 其它 >關於java8新特性lambda應用場景之函式式介面的理解

關於java8新特性lambda應用場景之函式式介面的理解

外觀模式提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
**最少知識原則: **只和你的密友談話。

我們已經知道介面卡模式是如何將一個類的介面轉換成另一個符合客戶期望的介面的。現在我們要看一個改變介面的新模式,但是它改變介面的原因是為了簡化介面。這個模式被巧妙地命名為外觀模式,之所以這麼稱呼,是因為它將一個或數個類的複雜的一切都隱藏在背後,只顯露出一個乾淨美好的外觀。

甜蜜的家庭影院

在我們進入外觀模式的細節之前,讓我們看一個風行全美的熱潮:建立自己的家庭影院。
通過一番研究比較,你組裝了一套殺手級的系統,內含DVD播放器、投影機、自動螢幕、環繞立體聲,甚至還有爆米花機。
你花了好幾個星期佈線、掛上投影機、連線所有的裝置並進行微調。現在,你準備開始享受一部電影……
挑選一部DVD影片,放鬆,準備開始感受電影的魔幻魅力。哎呀!忘了一件事:想看電影,必須先執行一些任務:

  1. 開啟爆米花機;
  2. 開始爆米花;
  3. 將燈光調暗;
  4. 放下螢幕;
  5. 開啟投影機;
  6. 將投影機的輸入切換到DVD;
  7. 將投影機設定在寬屏模式;
  8. 開啟功放;
  9. 將功放的輸入設定為DVD;
  10. 將功放設定為環繞立體聲;
  11. 將功放音量調到中;
  12. 開啟DVD播放器;
  13. 開始播放DVD。
    讓我們將這些任務寫成類和方法的呼叫:
// 開啟爆米花機,開始爆米花
popper.on();
popper.pop();

// 燈光調到10%的亮度
lights.dim(10);

// 把螢幕放下來
screen.down();

// 開啟投影機,並將它設定在寬屏模式
projector.on();
projector.setInput(dvd);
projector.wideScreenMode();

// 開啟功放,設定為DVD,調整成環繞立體聲模式,音量調到5
amp.on();
amp.setDvd(dvd);
amp.setSurroundSound();
amp.setVolume(5);

// 開啟DVD機,“終於”可以看電影了!
dvd.on();
dvd.play(movies);

但還不只這樣:
看完電影后,你還要把一切都關掉,怎麼辦?難道要反向地把這一切動作再進行一次?
如果要聽CD或者廣播,難道也會這麼麻煩?
如果你決定要升級你的系統,可能還必須重新學習一套稍微不同的操作過程。
怎麼辦?使用你的家庭影院竟變得如此複雜!讓我們看看外觀模式如何解決這團混亂,好讓你能輕易地享受電影。

構造家庭影院外觀

外觀模式,通過實現一個提供更合理的介面的外觀類,你可以將一個複雜的子系統變得容易使用。如果你需要複雜子系統的強大威力,別擔心,還是可以使用原來的複雜介面的;但如果你需要的是一個方便使用的介面,那就使用外觀。
外觀類將家庭影院的諸多元件視為一個系統,通過呼叫這個子系統,來實現watchMovie()方法。
客戶程式碼可以呼叫此家庭影院外觀所提供的方法,而不必再呼叫這個子系統的方法。所以,想要看電影,我們只要呼叫一個方法(也就是watchMovie())就可以 == 燈光、DVD播放器、投影機、功放、螢幕、爆米花
外觀只是提供你更直接的操作,並未將原來的子系統阻隔起來。如果你需要子系統類的更高層功能,還是可以使用原來的子系統。

構造家庭影院外觀:
第一步是使用組合讓外觀能夠訪問子系統中所有的元件。

public class HomeTheaterFacade {
    // 這就是組合:我們會用到的子系統元件全部在這裡
    Amplifier amp;
    Tuner tuner;
    DvdPlayer dvd;
    CdPlayer cd;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    PopcornPopper popper;

    // 外觀將子系統中每一個元件的引用都傳入它的構造器中。
    // 然後外觀把它們賦值給相應的例項變數
    public HomeTheaterFacade(Amplifier amp,
                             Tuner tuner,
                             DvdPlayer dvd,
                             CdPlayer cd,
                             Projector projector,
                             TheaterLights lights,
                             Screen screen,
                             PopcornPopper popper) {
        this.amp = amp;
        this.tuner = tuner;
        this.dvd = dvd;
        this.cd = cd;
        this.projector = projector;
        this.lights = lights;
        this.screen = screen;
        this.popper = popper;
    }
}

現在該是時候將子系統的元件整合成一個統一的介面了。讓我們實現watchMovie()和endMovie()方法。

public void watchMovie(String movie){
    // watchMovie()將我們之前手動進行的每項任務依次處理。
    // 請注意,每項任務都是委託子系統中相應的元件處理的。
    System.out.println("Get ready to watch a movie");
    popper.on();
    popper.pop();
    lights.dim(10);
    screen.down();
    projector.on();
    projector.wideScreenMode();
    amp.on();
    amp.setDvd(dvd);
    amp.setSurroundSound();
    amp.setVolume(5);
    dvd.on();
    dvd.play(movie);
}

public void endMovie(){
    // endMovie()負責關閉一切。每項任務也是委託子系統中合適的元件處理的。
    System.out.println("Shutting movie theater down");
    popper.off();
    lights.on();
    screen.up();
    projector.off();
    amp.off();
    dvd.stop();
    dvd.eject();
    dvd.off();
}

現在,讓我們用輕鬆的方式去觀賞電影:

HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, lights, screen, popper);
homeTheaterFacade.watchMovie("Pulp Fiction");
homeTheaterFacade.endMovie();

定義外觀模式

想要使用外觀模式,我們建立了一個介面簡化而統一的類,用來包裝子系統中一個或多個複雜的類。外觀模式允許我們讓客戶和子系統之間避免緊耦合。
外觀模式提供了一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。

最少知識原則

** 最少知識原則 -- 只和你的密友談話。**

這當你正在設計一個系統,不管是任何物件,你都要注意它所互動的類有哪些,並注意它和這些類是如何互動的。
這個原則希望我們在設計中,不要讓太多的類耦合在一起,免得修改系統中一部分,會影響到其他部分。如果許多類之間相互依賴,那麼這個系統會變成一個易碎的系統,它需要花許多成本維護,也會因為太複雜而不容易被其他人瞭解。
究竟要怎樣才能避免這樣呢?這個原則提供了一些方針:就任何物件而言,在該物件的方法內,我們只應該呼叫屬於以下範圍的方法:
  1. 該物件本身;
  2. 被當做方法的引數而傳遞進來的物件;
  3. 此方法所建立或例項化的任何物件;
  4. 物件的任何元件。
這聽起來有點嚴厲,不是嗎?如果呼叫從另一個呼叫中返回的物件的方法,會有什麼害處呢?如果我們這樣做,相當於向另一個物件的子部分發請求(而增加我們直接認識的物件數目)。在這種情況下,原則要我們改為要求該物件為我們做出請求,這麼一來,我們就不需要認識該物件的元件了(讓我們的朋友圈子維持在最小的狀態)。比方說:
'前者需要依賴Thermometer類,後者並不需要'
 

// 這裡,我們從氣象站取得了溫度計物件,然後再從溫度計物件取得溫度
public float getTemp(){
    Thermometer thermometer = station.getThermometer();
    // 違反最少知識.原則了,因為在此呼叫的方法屬於另一次呼叫的返回物件。
    return thermometer.getTemperature();
    
}

// 在應用最少知識原則時,我們在氣象站中加進一個方法,用來向溫度計請求溫度。
// 這可以減少我們所依賴的類的數目
public float getTemp(){
    return station.getTemperature();
}