外觀模式(學習筆記)

  1. 意圖

  爲子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用java

  2. 動機

  將一個系統劃分紅若干個子系統有利於下降系統的複雜性。一個常見的設計目標是使子系統間的通訊和相互依賴關係達到最小。達到該目標的途徑之一就是引入一個外觀對象,他爲子系統中較通常的設施提供了一個單一而簡單的界面程序員

 

   例若有一個編程環境,它容許應用程序訪問它的編譯子系統。這個編譯子系統包含了若干個類來實現這一編譯器,如Scanner,Parser,ProgramNode,BytecodeStream和ProgramNodeBuilder。可是對於大多數編譯器的用戶並不關心語法分析和代碼生成這樣的細節,他們只是但願編譯一些代碼。編譯子系統提供了一個Compiler類,這個類定義了一個編譯器功能的統一接口。Compiler類是一個外觀,它給用戶提供了一個單一而簡單的編譯子系統接口。編譯器的外觀能夠方便大多數程序員使用,同時對少數懂得如何使用底層功能的人,它並不隱藏這些功能編程

 

 

  3. 適用性

  • 當要爲一個複雜子系統提供一個簡單接口時。子系統每每由於不斷演化而變得愈來愈複雜,大多數模式使用時都會產生更多更小的類。這使得子系統更具備可複用性,也更容易對子系統進行定製,但也給一些不須要定製子系統的用戶帶來一些使用上的困難。Facade能夠提供一個簡單的缺省視圖,以方便大多數用戶的使用
  • 客戶程序與抽象類的實現部分之間存在着很大的依賴性。引入Facade將這個子系統與客戶以及其餘的子系統分離,能夠提升子系統的獨立性和可移植性
  • 當須要構建一個層次結構的子系統時,使用Facade模式定義子系統中每層的入口點。若是子系統之間是相互依賴的,可讓它們僅經過Facade進行通訊,從而簡化了它們之間的依賴關係(有點相似中介者模式)

  4. 結構

 

  5. 效果

  1) 它對客戶屏蔽子系統組件,於是減小了客戶處理的對象數目並使得子系統使用起來更加方便緩存

  2) 實現了子系統和客戶之間的鬆耦合關係,而子系統內部的功能組件每每是緊耦合的。鬆耦合關係使得子系統的組件變化不會影響到它的客戶。Facade模式有助於創建層次結構系統,也有助於對對象之間的依賴關係分層。Facade模式能夠消除複雜的循環依賴關係ide

  3) 若是須要,該模式並不限制使用子系統類ui

  6. 代碼實現

   some_complex_media_library/VideoFile.javathis

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 20:59
 */
public class VideoFile {
    private String name;
    private String codecType;

    public VideoFile(String name) {
        this.name = name;
        this.codecType = name.substring(name.indexOf(".") + 1);
    }

    public String getCodecType() {
        return codecType;
    }

    public String getName() {
        return name;
    }
}

  some_complex_media_library/Codec.javaspa

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 20:59
 */
public interface Codec {
}

  some_complex_media_library/MPEG4CompressionCodec.java設計

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:00
 */
public class MPEG4CompressionCodec implements Codec{
    public String type = "mp4";
}

  some_complex_media_library/OggCompressionCodec.java代理

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:00
 */
public class OggCompressionCodec implements Codec{
    public String type = "ogg";
}

  some_complex_media_library/CodecFactory.java

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:01
 */
public class CodecFactory {
    public static Codec extract(VideoFile file) {
        String type = file.getCodecType();
        if (type.equals("mp4")) {
            System.out.println("CodecFactory: extracting mpeg audio...");
            return new MPEG4CompressionCodec();
        }
        else {
            System.out.println("CodecFactory: extracting ogg audio...");
            return new OggCompressionCodec();
        }
    }
}

  some_complex_media_library/BitrateReader.java

package facade.some_complex_media_library;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:01
 */
public class BitrateReader {
    public static VideoFile read(VideoFile file, Codec codec) {
        System.out.println("BitrateReader: reading file...");
        return file;
    }

    public static VideoFile convert(VideoFile buffer, Codec codec) {
        System.out.println("BitrateReader: writing file...");
        return buffer;
    }
}

  some_complex_media_library/AudioMixer.java

package facade.some_complex_media_library;

import java.io.File;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:01
 */
public class AudioMixer {
    public File fix(VideoFile result){
        System.out.println("AudioMixer: fixing audio...");
        return new File("tmp");
    }
}

  facade/VideoConversionFacade.java: 外觀提供了進行視頻轉換的簡單接口

package facade.facade;

import facade.some_complex_media_library.*;

import java.io.File;

/**
 * @author GaoMing
 * @date 2021/7/19 - 21:02
 */
public class VideoConversionFacade {
    public File convertVideo(String fileName, String format) {
        System.out.println("VideoConversionFacade: conversion started.");
        VideoFile file = new VideoFile(fileName);
        Codec sourceCodec = CodecFactory.extract(file);
        Codec destinationCodec;
        if (format.equals("mp4")) {
            destinationCodec = new OggCompressionCodec();
        } else {
            destinationCodec = new MPEG4CompressionCodec();
        }
        VideoFile buffer = BitrateReader.read(file, sourceCodec);
        VideoFile intermediateResult = BitrateReader.convert(buffer, destinationCodec);
        File result = (new AudioMixer()).fix(intermediateResult);
        System.out.println("VideoConversionFacade: conversion completed.");
        return result;
    }
}

  Demo.java: 客戶端代碼

package facade;

import facade.facade.VideoConversionFacade;

import java.io.File;

/**
 * @author GaoMing
 * @date 2021/7/19 - 20:59
 */
public class Demo {
    public static void main(String[] args) {
        VideoConversionFacade converter = new VideoConversionFacade();
        File mp4Video = converter.convertVideo("youtubevideo.ogg", "mp4");
        // ...
    }
}

  執行結果

VideoConversionFacade: conversion started.
CodecFactory: extracting ogg audio...
BitrateReader: reading file...
BitrateReader: writing file...
AudioMixer: fixing audio...
VideoConversionFacade: conversion completed.

 

  7. 與其餘模式的關係

  • 外觀模式爲現有對象定義了一個新接口,適配器模式則會試圖運用已有的接口。適配器一般只封裝一個對象,外觀一般會做用於整個對象子系統上
  • 當只需對客戶端代碼隱藏子系統建立對象的方式時, 你可使用抽象工廠模式來代替外觀
  • 享元模式展現瞭如何生成大量的小型對象, 外觀則展現瞭如何用一個對象來表明整個子系統
  • 外觀和中介者模式的職責相似:它們都嘗試在大量緊密耦合的類中組織起合做
    - 外觀爲子系統中的全部對象定義了一個簡單接口, 可是它不提供任何新功能。子系統自己不會意識到外觀的存在。子系統中的對象能夠直接進行交流
    - 中介者將系統中組件的溝通行爲中心化。各組件只知道中介者對象, 沒法直接相互交流

  • 外觀類一般能夠轉換爲單例模式類,由於在大部分狀況下一個外觀對象就足夠了
  • 外觀與代理模式的類似之處在於它們都緩存了一個複雜實體並自行對其進行初始化。代理與其服務對象遵循同一接口,使得本身和服務對象能夠互換,在這一點上它與外觀不一樣

  8. 已知應用

  • javax.faces.context.FacesContext 在底層使用了 Life­Cycle、View­Handler 和 Navigation­Handler 這幾個類,但絕大多數客戶端不知道
  • javax.faces.context.ExternalContext 在內部使用了 Servlet­Context、Http­Session、Http­Servlet­Request、Http­Servlet­Response 和其餘一些類

  識別方法:外觀能夠經過使用簡單接口,但將絕大部分工做委派給其餘類的類來識別。一般狀況下,外觀管理着其所使用的對象的完整生命週期

相關文章
相關標籤/搜索