《Head First 設計模式》:外觀模式

驚卻一目發表於2020-08-24

正文

一、定義

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

要點:

  • 外觀模式將一個或數個類的複雜的一切都隱藏在背後,只顯露出一個乾淨美好的外觀。
  • 通過將子系統的方法封裝到外觀的方法中,可以達到對子系統的“一鍵操作”。
  • 外觀模式的意圖是簡化介面,好讓一個子系統更易於使用。
  • 外觀模式將客戶從元件的子系統中解耦。

二、實現步驟

1、建立子系統元件類

(1)子系統元件A

/**
 * 子系統元件A
 */
public class ComponentA {
    
    public void action() {
        System.out.println("ComponentA action...");
    }
}

(2)子系統元件B

/**
 * 子系統元件B
 */
public class ComponentB {

    public void action() {
        System.out.println("ComponentB action...");
    }
}

(3)子系統元件C

/**
 * 子系統元件C
 */
public class ComponentC {
    
    public void action() {
        System.out.println("ComponentC action...");
    }
}

2、建立外觀類

外觀類的方法封裝了子系統元件的一系列方法。這樣,客戶就可以通過外觀類的方法,來一次性呼叫一系列子系統元件的方法。而不是一個個去呼叫子系統元件的方法。

/**
 * 外觀類
 */
public class Facade {
    
    ComponentA componentA;
    ComponentB componentB;
    ComponentC componentC;
    
    public Facade(ComponentA componentA,
            ComponentB componentB,
            ComponentC componentC) {
        this.componentA = componentA;
        this.componentB = componentB;
        this.componentC = componentC;
    }

    /**
     * 通過外觀類,請求子系統元件
     */
    public void request() {
        componentA.action();
        componentB.action();
        componentC.action();
    }
}

3、使用外觀訪問子系統元件

public class Test {
    
    public static void main(String[] args) {
        // 子系統元件
        ComponentA componentA = new ComponentA();
        ComponentB componentB = new ComponentB();
        ComponentC componentC = new ComponentC();
        // 外觀類
        Facade facade = new Facade(componentA, componentB, componentC);
        facade.request();
    }
}

三、舉個例子

1、背景

假設你打算建立自己的家庭影院,通過一番研究比較,你組裝了一套殺手級的系統,內含 DVD 播放器、投影機、自動螢幕、環繞立體聲,甚至還有爆米花機。

你花了幾個星期佈線、掛上投影機、連線所有的裝置並進行微調。現在你打算播放一部 DVD 影片放鬆一下。

但是你發現,在看電影前,必須先進行一系列操作:開啟爆米花機 -> 開始爆米花 -> 將燈光調暗 -> 放下螢幕 -> 開啟投影機 -> 將投影機的輸入切換到 DVD -> 將投影機設定在寬屏模式 -> 開啟功放 -> 將功放的輸入設定為 DVD -> 將功放設定為環繞立體聲 -> 將功放音量調到中(5) -> 開啟 DVD 播放器 -> 開始播放 DVD。

不僅如此,看完電影后,你還要把一切都關掉。使用你的家庭影院竟變得如此複雜!於是你決定升級你的系統……

2、實現

使用外觀模式將看電影相關的一系列操作,封裝到外觀的 watchMovie() 方法中。這樣一來,要看電影的時候,只需要進行一個“看電影”的操作就行了。同理,可將看完電影相關的一系列操作,封裝到 endMovie() 方法中。

(1)建立家庭影院子系統元件

/**
 * 功放
 */
public class Amplifier {
    
    /**
     * 開啟功放
     */
    public void on() {
        System.out.println("Top-O-Line Amplifier on");
    }
    
    /**
     * 關閉功放
     */
    public void off() {
        System.out.println("Top-O-Line Amplifier off");
    }
    
    /**
     * 設定DVD
     */
    public void setDvd(DvdPlayer dvd) {
        System.out.println("Top-O-Line Amplifier setting DVD player to Top-O-Line DVD Player");
    }
    
    /**
     * 設定為環繞立體聲
     */
    public void setSurroundSound() {
        System.out.println("Top-O-Line Amplifier surround sound on (5 speakers, 1 subwoofer)");
    }
    
    /**
     * 調節音量
     */
    public void setVolume(int volume) {
        System.out.println("Top-O-Line Amplifier setting volume to " + volume);
    }
}
/**
 * DVD播放器
 */
public class DvdPlayer {
    
    /**
     * 開啟DVD播放器
     */
    public void on() {
        System.out.println("Top-O-Line DVD Player on");
    }
    
    /**
     * 關閉DVD播放器
     */
    public void off() {
        System.out.println("Top-O-Line DVD Player off");
    }
    
    /**
     * 播放DVD
     */
    public void play(String movie) {
        System.out.println("Top-O-Line DVD Player playing “" + movie + "”");
    }
    
    /**
     * 停止播放DVD
     */
    public void stop() {
        System.out.println("Top-O-Line DVD Player stop");
    }
    
    /**
     * 彈出DVD
     */
    public void eject() {
        System.out.println("Top-O-Line DVD Player eject");
    }
}
/**
 * 投影儀
 */
public class Projector {
    
    /**
     * 開啟投影儀
     */
    public void on() {
        System.out.println("Top-O-Line Projector on");
    }
    
    /**
     * 關閉投影儀
     */
    public void off() {
        System.out.println("Top-O-Line Projector off");
    }
    
    /**
     * 設為寬屏模式
     */
    public void wideScreenMode() {
        System.out.println("Top-O-Line Projector in widescreen mode (16x9 aspect ratio)");
    }
}
/**
 * 影院燈光
 */
public class TheaterLights {
    
    /**
     * 開啟燈光
     */
    public void on() {
        System.out.println("Theater Ceiling Lights on");
    }
    
    /**
     * 調暗燈光
     */
    public void dim(int level) {
        System.out.println("Theater Ceiling Lights dimming to " + level + "%");
    }
}
/**
 * 螢幕
 */
public class Screen {
    
    /**
     * 放下螢幕
     */
    public void down() {
        System.out.println("Theater Screen going down");
    }
    
    /**
     * 升起螢幕
     */
    public void up() {
        System.out.println("Theater Screen going up");
    }
}
/**
 * 爆米花機
 */
public class PopcornPopper {
    
    /**
     * 開啟爆米花機
     */
    public void on() {
        System.out.println("Popcorn Popper on");
    }
    
    /**
     * 關閉爆米花機
     */
    public void off() {
        System.out.println("Popcorn Popper off");
    }
    
    /**
     * 開始爆米花
     */
    public void pop() {
        System.out.println("Popcorn Popper popping popcorn!");
    }
}

(2)建立家庭影院外觀

/**
 * 家庭影院外觀
 */
public class HomeTheaterFacade {
    
    Amplifier amp;
    DvdPlayer dvd;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    PopcornPopper popper;
    
    public HomeTheaterFacade(Amplifier amp,
            DvdPlayer dvd,
            Projector projector,
            TheaterLights lights,
            Screen screen,
            PopcornPopper popper) {
        this.amp = amp;
        this.dvd = dvd;
        this.projector = projector;
        this.lights = lights;
        this.screen = screen;
        this.popper = popper;
    }

    /**
     * 看電影
     */
    public void watchMovie(String movie) {
        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() {
        System.out.println("Shuting movie theater down...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        dvd.stop();
        dvd.eject();
        dvd.off();
    }
}

(3)使用家庭影院外觀觀看電影

public class Test {
    
    public static void main(String[] args) {
        // 子系統元件
        Amplifier amp = new Amplifier();
        DvdPlayer dvd = new DvdPlayer();
        Projector projector = new Projector();
        TheaterLights lights = new TheaterLights();
        Screen screen = new Screen();
        PopcornPopper popper = new PopcornPopper();
        // 家庭影院外觀
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, dvd, projector, lights, screen, popper);
        // 看電影
        homeTheater.watchMovie("Raiders of the Lost Ark");
        // 看完電影
        homeTheater.endMovie();
    }
}

相關文章