開發之路(設計模式八:外觀模式)

改變接口的新模式,爲了簡化接口

此次帶來的模式爲外觀模式,之因此這麼稱呼,由於它將一個或多個類複雜的一切都隱藏起來。 編程

我依舊舉生活中例子,如今有些朋友家的液晶電視多是大尺寸的,或者有用投影儀來看電視,打遊戲的。有一天我想用家庭影院系統在家裏看一次大片。設計模式

一、打開爆米花機
二、開始爆米花
三、將燈光調暗
四、放下屏幕
五、打開投影儀
六、將投影儀的輸入切換到DVD
七、將投影儀設置在寬屏模式下
八、打開功放
九、將功放的輸入設置爲DVD
十、將功放的設置爲環繞立體聲
十一、功放音量調到中(5)
十二、打開DVD播放器
1三、開始播放DVD

等我操做完這些我才能開始享受大片,須要打開這麼多開關。。並且若是看完要關閉是否是又要反向把動做再來一遍,這樣或許連我都沒興趣使用影院系統了。也許這套系統該升級了!!ide

這時候外觀模式就發揮做用了,經過實現一個提供更合理的接口的外觀類,讓一個複雜的系統變得使用簡單了,
咱們來看看外觀是怎麼運做的。如圖(可點擊查看原圖)
圖片描述測試

這裏注意:
一、外觀不僅是簡化了接口,也將客戶從組件的子系統中解耦,若客戶有須要仍是可使用子系統,外觀是爲了簡化接口。
二、外觀和適配器模式能夠包裝許多類,可是外觀的意圖是簡化接口,而適配器的意圖是將接口轉換成不一樣的接口,換句話說是讓兩個本來不適用的東西,變得能相互使用同樣。this

如今開始咱們的家庭影院系統升級把~~~~spa

家庭影院類(外觀)設計

package headfirst.facade.hometheater;

/**
 * 家庭影院 (將各個組件統一的「接口」)
 * 
 * @author Joy
 * 
 */
// 外觀類
public class HomeTheaterFacade {
    /**
     * 組合,將用到的子系統組件所有都在這裏
     */
    Amplifier amp;// 擴音器
    Tuner tuner;// 無線電收音機
    DvdPlayer dvd;// DVD播放器
    CdPlayer cd;// CD播放器
    Projector projector;// 投影儀
    TheaterLights lights;// 燈光
    Screen screen;// 屏幕
    PopcornPopper popper;// 爆米花機

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

    /**
     * 將子系統的組件整合成一個統一的接口 watchMovie()方法 就至關於把全部操做放在一個方法裏,簡化操做
     * 將咱們以前手動進行的每項任務我依次處理。 注意:每項任務都是具體實現都是委託子系統中相應的組件處理的
     * 
     * @param movie
     */
    public void watchMovie(String movie) {
        System.out.println("準備好,看電影了...");
        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);
    }

    /**
     * endMovie() 負責關閉一切,每項任務也都是委託子系統中對應組件的具體方法
     */
    public void endMovie() {
        System.out.println("關閉電影...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        dvd.stop();
        dvd.eject();
        dvd.off();
    }

    /**
     * 下面這項方法,若客戶仍是須要調用子系統的方法話,相應調用便可
     * 
     * @param cdTitle
     */
    public void listenToCd(String cdTitle) {
        System.out.println("Get ready for an audiopile experence...");
        lights.on();
        amp.on();
        amp.setVolume(5);
        amp.setCd(cd);
        amp.setStereoSound();
        cd.on();
        cd.play(cdTitle);
    }

    public void endCd() {
        System.out.println("Shutting down CD...");
        amp.off();
        amp.setCd(cd);
        cd.eject();
        cd.off();
    }

    public void listenToRadio(double frequency) {
        System.out.println("Tuning in the airwaves...");
        tuner.on();
        tuner.setFrequency(frequency);
        amp.on();
        amp.setVolume(5);
        amp.setTuner(tuner);
    }

    public void endRadio() {
        System.out.println("Shutting down the tuner...");
        tuner.off();
        amp.off();
    }
}

下面是各個組件類(子系統)code

package headfirst.facade.hometheater;

/**
 * 擴音器類
 * 
 * @author Joy
 * 
 */
public class Amplifier {
    // 音響類型
    String description;
    Tuner tuner;
    DvdPlayer dvd;
    CdPlayer cd;

    public Amplifier(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " 開啓");
    }

    public void off() {
        System.out.println(description + " 關閉");
    }

    public void setStereoSound() {
        System.out.println(description + " 環繞立體模式");
    }

    public void setSurroundSound() {
        System.out.println(description + " 環繞聲設置(5 音量, 1 低音炮)");
    }

    public void setVolume(int level) {
        System.out.println(description + " 設置音量: " + level);
    }

    public void setTuner(Tuner tuner) {
        System.out.println(description + "設置音效 " + dvd);
        this.tuner = tuner;
    }

    public void setDvd(DvdPlayer dvd) {
        System.out.println(description + " 設置DVD播放器 " + dvd);
        this.dvd = dvd;
    }

    public void setCd(CdPlayer cd) {
        System.out.println(description + " 設置CD播放器" + cd);
        this.cd = cd;
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;

/**
 * CD播放器
 * 
 * @author Joy
 * 
 */
public class CdPlayer {
    String description;
    int currentTrack;
    Amplifier amplifier;
    String title;

    public CdPlayer(String description, Amplifier amplifier) {
        this.description = description;
        this.amplifier = amplifier;
    }

    public void on() {
        System.out.println(description + " 開啓");
    }

    public void off() {
        System.out.println(description + " 關閉");
    }

    public void eject() {
        title = null;
        System.out.println(description + " 彈出");
    }

    public void play(String title) {
        this.title = title;
        currentTrack = 0;
        System.out.println(description + " 播放 \"" + title + "\"");
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;

/**
 * DVD播放器
 * 
 * @author Joy
 * 
 */
public class DvdPlayer {
    String description;
    int currentTrack;
    Amplifier amplifier;
    String movie;

    public DvdPlayer(String description, Amplifier amplifier) {
        this.description = description;
        this.amplifier = amplifier;
    }

    public void on() {
        System.out.println(description + " 開啓");
    }

    public void off() {
        System.out.println(description + " 關閉");
    }

    public void eject() {
        movie = null;
        System.out.println(description + " 彈出");
    }

    public void play(String movie) {
        this.movie = movie;
        currentTrack = 0;
        System.out.println(description + " 播放 \"" + movie + "\"");
    }

    public void play(int track) {
        if (movie == null) {
            System.out.println(description + " can't play track " + track
                    + " no dvd inserted");
        } else {
            currentTrack = track;
            System.out.println(description + " playing track " + currentTrack
                    + " of \"" + movie + "\"");
        }
    }

    public void stop() {
        currentTrack = 0;
        System.out.println(description + " 中止 \"" + movie + "\"");
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;

/**
 * 爆米花機類
 * 
 * @author Joy
 * 
 */
public class PopcornPopper {
    String description;

    public PopcornPopper(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " 開啓");
    }

    public void off() {
        System.out.println(description + " 關閉");
    }

    public void pop() {
        System.out.println(description + "正在工做!");
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;
/**
 * 投影儀類
 * @author Joy
 *
 */
public class Projector {
    String description;
    DvdPlayer dvdPlayer;
    
    public Projector(String description, DvdPlayer dvdPlayer) {
        this.description = description;
        this.dvdPlayer = dvdPlayer;
    }
 
    public void on() {
        System.out.println(description + " 開啓");
    }
 
    public void off() {
        System.out.println(description + " 關閉");
    }

    public void wideScreenMode() {
        System.out.println(description + " 設置成寬屏模式 (16x9 高寬比)");
    }

    public void tvMode() {
        System.out.println(description + " 設置爲TV模式 (4x3 高寬比)");
    }
  
        public String toString() {
                return description;
        }
}
package headfirst.facade.hometheater;

/**
 * 屏幕類
 * 
 * @author Joy
 * 
 */
public class Screen {
    String description;

    public Screen(String description) {
        this.description = description;
    }

    public void up() {
        System.out.println(description + " 上升");
    }

    public void down() {
        System.out.println(description + " 降下");
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;

/**
 * 影院燈光
 * 
 * @author Joy
 * 
 */
public class TheaterLights {
    String description;

    public TheaterLights(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " 打開");
    }

    public void off() {
        System.out.println(description + " 關閉");
    }

    public void dim(int level) {
        System.out.println(description + " 掉亮度爲: " + level + "%");
    }

    public String toString() {
        return description;
    }
}
package headfirst.facade.hometheater;

public class Tuner {
    String description;
    Amplifier amplifier;
    double frequency;

    public Tuner(String description, Amplifier amplifier) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " on");
    }

    public void off() {
        System.out.println(description + " off");
    }

    public void setFrequency(double frequency) {
        System.out.println(description + " setting frequency to " + frequency);
        this.frequency = frequency;
    }

    public String toString() {
        return description;
    }
}

測試類(用輕鬆方式看電影)對象

package TestMain;

import headfirst.facade.hometheater.Amplifier;
import headfirst.facade.hometheater.CdPlayer;
import headfirst.facade.hometheater.DvdPlayer;
import headfirst.facade.hometheater.HomeTheaterFacade;
import headfirst.facade.hometheater.PopcornPopper;
import headfirst.facade.hometheater.Projector;
import headfirst.facade.hometheater.Screen;
import headfirst.facade.hometheater.TheaterLights;
import headfirst.facade.hometheater.Tuner;

/**
 * 外觀做用簡化接口 
 * 適配器做用是將接口能與另外一個接口相匹配
 * 
 * @author Joy
 * 
 */
public class HomeTheaterTestDrive {
    public static void main(String[] args) {
        // 將各個組件都實例化
        Amplifier amp = new Amplifier("Top-O-Line 擴音器");
        Tuner tuner = new Tuner("Top-O-Line AM/FM 調諧器", amp);
        DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD 播放器", amp);
        CdPlayer cd = new CdPlayer("Top-O-Line CD 播放器", amp);
        Projector projector = new Projector("Top-O-Line 投影儀", dvd);
        TheaterLights lights = new TheaterLights("影院天花板燈");
        Screen screen = new Screen("影院屏幕");
        PopcornPopper popper = new PopcornPopper("爆米花機");

        // 實例化外觀
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd,
                cd, projector, screen, lights, popper);
        // 使用簡化的開啓關閉接口
        homeTheater.watchMovie("《奪寶奇兵》");
        homeTheater.endMovie();
    }
}

效果圖
圖片描述接口

是否是感到很輕鬆了,我只須要「放入」我想看的電影,剩下一切程序自動化完成。

外觀模式定義:提供了一個統一的接口,用來訪問子系統中的一羣接口。外觀定義了一個高層接口,讓子系統更容易使用。

再來一張圖來理解外觀
圖片描述

這裏就引出一個「最少知識」原則
最少知識原則告訴咱們要減小對象之間的交互,只留下幾個「密友」,當你在設計一個系統的時候,,不論是任何對象,都要注意它所交互的類有哪些,並注意它和這些類是如何交互的。
這個原則但願咱們設計中,不要讓太多的類耦合在一塊兒,省得修改系統一部分,就會影響到其餘部分。若是許多類之間相互依賴,那麼系統就會變得牽一髮而動全身了也由於要複雜而不容易被人理解。

要點:
一、當須要簡化並統一一個很大的接口或者一羣複雜的接口時,使用外觀。
二、外觀將客戶從一個複雜的子系統中解耦出來。
三、實現一個外觀,將子系統組合委託給外觀,而後外觀將工做讓子系統執行。

感謝你看到這裏,外觀模式到這裏就結束了,本人文筆隨便,如有不足或錯誤之處望給予指點,90度彎腰~~~很快我會發佈下一個設計模式的內容,生命不息,編程不止!

參考書籍:《Head First 設計模式》
相關文章
相關標籤/搜索