天天看點

設計之禅——外觀模式概述定義Coding最少知道原則總結

概述

平時在我們生活中,我們常常會接觸學習各種各樣的新事物,而能夠快速吸引留住大量客戶的都有一個共性,就是簡單易學好上手。比如,windows和linux系統,前者比後者更加普及的原因也就是不需要經過專業系統的學習就能輕松使用。同樣的,這種思想在程式設計界有一個專業的術語——外觀模式。

定義

首先我們來看看它的定義:

外觀模式定義了一個統一的接口,用來通路子系統中的一群接口,使得子系統更容易使用。

概念比較簡單,也很容易懂,不過還是有些抽象,下面我通過一個例子來具體講講:想象一下你剛住進你的新家,如你所想的布置了 一套家庭影院系統(投屏、音箱、燈光等)。當你下班回家時,你想先泡個澡,然後開啟家庭影院系統,享受惬意的生活。但是,每次回去你都得一個個的将浴缸水放上,打開燈、電視等,之後又得一個個關上,這樣繁雜的操作反而會令人感到煩躁。而外觀模式的作用就是他提供給你一個統一的操作按鈕(比如叫影院模式),你隻需要按下這一個按鈕上述的家居就都自動開始工作了,看完之後再按下統一的關閉按鈕就行,這樣我們就能更加的惬意地享受下班生活了(PS:我之前寫過一篇關于指令模式的文章,裡面有一個關于指令party模式的例子,兩者非常相似,注意區分本質的意圖)。是以外觀模式幫助我們屏蔽掉了底層那些繁雜的操作,不過他并沒有屏蔽掉你對底層的直接操作,比如洗完澡就可以自動清洗浴缸了,你就可以直接按下浴缸的清洗按鈕就可以了,不用等到電影看完後再一起進行。

Coding

明白外觀模式的意圖和原理,代碼實作就非常容易了,首先是我們的智能家居類:

// 音箱
public class Amplifier {

    public void on() {
        System.out.println("TV is starting....");
    }

    public void off() {
        System.out.println("TV has stopped!");
    }

    public void setCd() {
        System.out.println("CD has set!");
    }

}

// 燈光
public class RoomLamp {

    public void on() {
        System.out.println("Light on!");
    }

    public void off() {
        System.out.println("Light off!");
    }

}

// 浴缸
public class Bathtub {

    public void on() {
        System.out.println("Bathtub is working!");
    }

    public void off() {
        System.out.println("Bathtub is stopped!");
    }

}

// 電視
public class TV {

    public void on() {
        System.out.println("TV is starting....");
    }

    public void off() {
        System.out.println("TV has stopped!");
    }

}           

複制

接着是我們的外觀類:

public class HomePartyFacade {

    private TV tv;
    private Bathtub bathtub;
    private RoomLamp roomLamp;
    private Amplifier amplifier;

    public HomePartyFacade(TV tv, Bathtub bathtub, RoomLamp roomLamp, Amplifier amplifier) {
        this.tv = tv;
        this.bathtub = bathtub;
        this.roomLamp = roomLamp;
        this.amplifier = amplifier;
    }

    public void startParty() {
        roomLamp.on();
        bathtub.on();
        amplifier.on();
        amplifier.setCd();
        tv.on();
    }

    public void endParty() {
        roomLamp.off();
        amplifier.off();
        tv.off();
    }

}           

複制

最後你隻需要調用startParty方法就可以開始看電影了,外觀模式就是這麼簡單。不過還沒完,外觀模式隐含了一個設計原則——最少知道原則(迪米特法則),那什麼是最少知道原則呢?

最少知道原則

簡單的說,一個類越少被其它類知道越好。為什麼呢?我相信大家從開始接觸程式設計起,就聽到過高内聚,低耦合的概念,避免在代碼修改時牽一發而動全身,最少知道原則就是為了降低各個類之間的耦合而努力。那要如何才能滿足這個原則呢?

它提供了一些方針,就任何對象而言,在該對象的方法内,我們隻調用屬于以下範圍的方法:
  • 該對象的本身;
  • 通過方法參數傳進的對象;
  • 目前方法執行個體化的所有對象;
  • 該對象的所有成員變量引用的對象。

簡單的說,也就是不要調用另外一次調用所傳回的對象的方法(即避免鍊式調用)。上面的例子裡沒有鍊式調用,但是對于使用者來說他隻想輕松的看場電影,而不想費時費力的去操作一個個開關,是以隻需要為他提供一個統一的操作接口,那就隻需要記住這個操作的使用就行了,也不用擔心以後更新了某些系統而又得去學一遍該如何操作新系統,廠家隻需要提供一個新的外觀就行了,極大的降低了使用者和子系統的耦合度。

不過,我們也不難看出,最少知道原則的缺陷就在于會産生許多的外觀中間類,也就使得系統變得更龐大和複雜。是以也不要盲目的遵循這一原則。

總結

外觀模式和裝飾者模式以及擴充卡模式都是通過組合來實作各自的目的,在需要簡化并統一一群複雜的接口時,使用外觀;需要改變接口以符合客戶的預期要求時使用擴充卡模式;而需要給對象增加新的行為和責任時使用裝飾者模式。