外观模式(学习笔记)

  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 和其余一些类

  识别方法:外观能够经过使用简单接口,但将绝大部分工做委派给其余类的类来识别。一般状况下,外观管理着其所使用的对象的完整生命周期

相关文章
相关标签/搜索