写点什么

09. 外观模式设计思想

作者:杨充
  • 2024-11-05
    湖北
  • 本文字数:5760 字

    阅读完需:约 19 分钟

09.外观模式设计思想

目录介绍

  • 01.外观模式基础

  • 1.1 外观模式由来

  • 1.2 外观模式定义

  • 1.3 外观模式场景

  • 1.4 外观模式思考

  • 1.5 解决的问题

  • 02.外观模式实现

  • 2.1 罗列一个场景

  • 2.2 外观结构

  • 2.3 外观基本实现

  • 2.4 有哪些注意点

  • 2.5 设计思想

  • 03.外观实例演示

  • 3.1 需求分析

  • 3.2 代码案例实现

  • 3.3 是否可以优化

  • 04.外观模式场景

  • 05.外观模式分析

  • 5.1 外观模式优点

  • 5.2 外观模式缺点

  • 5.3 适用环境

  • 5.4 模式拓展

  • 06.外观代理总结

  • 6.1 总结一下学习

  • 6.2 更多内容推荐

推荐一个好玩网站

一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网


https://yccoding.com/

01.外观模式基础

1.0 本博客 AI 摘要

外观模式设计思想:为了解决软件系统中的复杂性和耦合性问题,外观模式提供了一组统一的接口,简化客户端与子系统的交互。主要内容包括外观模式的基础、实现、实例演示、应用场景、优缺点及适用环境。通过创建外观类,将复杂系统的内部实现细节隐藏起来,只暴露出简化的接口给客户端,从而降低耦合度,提高系统的可维护性和可扩展性。

1.1 外观模式由来

外观模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,外观模式被引入。


门面模式原理和实现都特别简单,应用场景也比较明确,主要在接口设计方面使用。更多内容

1.2 外观模式定义

门面模式,也叫外观模式,英文全称是 Facade Design Pattern。


在 GoF 的《设计模式》一书中,门面模式是这样定义的:Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.


翻译成中文就是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。


外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

1.3 外观模式场景

应用场景:


  1. 医院接待:医院的接待人员简化了挂号、门诊、划价、取药等复杂流程。

  2. Java 三层架构:通过外观模式,可以简化对表示层、业务逻辑层和数据访问层的访问。

1.4 外观模式思考

外观模式的核心思想主要是通过创建一个外观类,将复杂系统的内部实现细节隐藏起来,只暴露出一个简化的接口给客户端。客户端只需要与外观类进行交互,而不需要直接与子系统的组件进行交互,从而达到想要的效果。


在思考外观模式时,可以考虑以下几个方面:


  1. 系统的复杂性:外观模式适用于系统的复杂性较高,包含多个子系统或模块的情况。

  2. 客户端的便利性:外观模式旨在提供一个简化的接口给客户端使用,使得客户端可以更方便地使用系统的功能,而不需要了解系统的内部实现细节。

  3. 系统的灵活性和可扩展性:外观模式可以提供系统的灵活性和可扩展性。

  4. 设计的一致性和封装性:外观模式可以提供设计的一致性和封装性。

1.5 解决的问题

主要解决的问题


  1. 降低客户端与复杂子系统之间的耦合度。

  2. 简化客户端对复杂系统的操作,隐藏内部实现细节。更多内容

02.外观模式实现

2.1 罗列一个场景

下面通过一个简单的例子来演示。假设有一个电脑系统,包含了多个子系统,如音乐功能、视频功能和联网功能。可以打开或者关闭某功能。

2.2 外观结构

外观模式包含如下角色:


  1. Facade: 外观角色。提供一个简化的接口,封装了系统的复杂性。外观模式的客户端通过与外观对象交互,而无需直接与系统的各个组件打交道。

  2. SubSystem:子系统角色。由多个相互关联的类组成,负责系统的具体功能。外观对象通过调用这些子系统来完成客户端的请求。

  3. Client:客户端。使用外观对象来与系统交互,而不需要了解系统内部的具体实现。

2.3 外观基本实现

实现方式


  1. 创建外观类:定义一个类(外观),作为客户端与子系统之间的中介。提供 Facade 接口,抽象出通用方法打开和关闭。

  2. 封装子系统操作:外观类将复杂的子系统操作封装成简单的方法。三个子系统类(Subsystem):音乐功能、视频功能和联网功能


提供一个简化的接口


public interface Facade {    void open();    void close();}
复制代码


创建三个子系统类(Subsystem):音乐功能、视频功能和联网功能。更多内容


public class Music implements Facade{        @Override    public void open() {        System.out.println("加载音乐");    }    @Override    public void stop() {        System.out.println("关闭音乐");    }}
public class Video implements Facade{
@Override public void open() { System.out.println("打开视频"); }
@Override public void stop() { System.out.println("关闭视频"); }}
public class Internet implements Facade{
@Override public void open() { System.out.println("连接网络"); }
@Override public void stop() { System.out.println("断开网络"); }}
复制代码


创建外观类(Facade) - 电脑系统


public class Computer {    private Music music;    private Video video;    private Internet internet;
public Computer() { this.music = new Music(); this.video = new Video(); this.internet = new Internet(); }
public void openVideo() { internet.open(); music.open(); video.open(); }
public void stopVideo() { video.stop(); music.stop(); internet.stop(); }}
复制代码


创建客户端(Client)


private void test() {    Computer computer = new Computer();    System.out.println("播放视频步骤:");    // 播放视频    computer.openVideo();    System.out.println("关闭视频步骤:");    // 关闭视频    computer.stopVideo();}
复制代码


在上述例子中,音乐功能、视频功能和联网功能是子系统,Computer 是外观类,封装了对这些子系统的调用,并提供了简化的接口给客户端。


在客户端中,我们使用外观模式简化了电脑系统的使用。通过调用外观类的方法,客户端无需直接与多个子系统交互,而是通过外观类来管理对子系统的调用。直接一个接口调用打开视频,打开音乐,连接网络功能


该案例中思考:如果不使用外观模式,客户端通常需要和子系统内部的多个模块交互,也就是说客户端会和这些模块之间都有依赖关系,任意一个模块的变动都可能会引起客户端的变动。


使用外观模式后,客户端只需要和外观类交互,即只和这个外观类有依赖关系,不需要再去关心子系统内部模块的变动情况了。更多内容,这样一来,客户端不但简单,而且这个系统会更有弹性。

2.4 有哪些注意点

外观模式并不是为了解决系统的性能问题,而是为了提供一个简化的接口和封装系统的复杂性。在使用外观模式时,需要权衡封装的程度和灵活性,并根据具体的需求和情况做出决策。

2.5 设计思想

比如该案例中:


  1. 针对音乐,视频,联网抽象出通用功能,定义成接口【打开和关闭】。充分体现出面向对象中抽象的设计思想!

  2. 针对音乐,视频,联网各个子系统之间的交互,将他们的逻辑封装到外观类中,充分体现出封装的原则!


外观模式的设计思想是基于封装和抽象的原则,通过将子系统的复杂性隐藏起来,提供一个简化的接口给客户端使用。这样可以提高系统的可维护性、可扩展性和可重用性,同时也使得客户端代码更加简洁和易于理解。

03.外观实例演示

3.1 需求分析

有个需求:我们知道在 UI 开发中,可以绘制很多图像。比如可以绘制圆形,绘制矩形,绘制椭圆形,绘制……来达到绘制显示的效果。


我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。更多内容

3.2 代码案例实现

创建一个接口。


public interface Shape {    void draw();}
复制代码


创建实现接口的实体类。


public class Rectangle implements Shape {    @Override   public void draw() {      System.out.println("Rectangle::draw()");   }}
public class Square implements Shape { @Override public void draw() { System.out.println("Square::draw()"); }}
public class Circle implements Shape { @Override public void draw() { System.out.println("Circle::draw()"); }}
复制代码


创建一个外观类。


public class ShapeMaker {   private Shape circle;   private Shape rectangle;   private Shape square;    public ShapeMaker() {      circle = new Circle();      rectangle = new Rectangle();      square = new Square();   }    public void drawCircle(){      circle.draw();   }   public void drawRectangle(){      rectangle.draw();   }   public void drawSquare(){      square.draw();   }}
复制代码


使用该外观类画出各种类型的形状。


private void test() {    ShapeMaker shapeMaker = new ShapeMaker();    shapeMaker.drawCircle();    shapeMaker.drawRectangle();    shapeMaker.drawSquare();}
复制代码

3.3 是否可以优化

比如,现在增加一个需求,绘制各种素材,不管是圆形,矩形,或者椭圆等,都需要创建画笔和画板,可以给绘制设置不同的颜色。如果是你,该如何设计!更多内容

05.外观模式分析

5.1 外观模式优点

  1. 简化接口:外观模式为子系统提供了一个简化的接口,使得调用者无需关心子系统的内部细节和复杂性,降低了系统的学习成本和使用难度。

  2. 降低耦合度:通过引入外观类,子系统与调用者之间的耦合度得到了降低。外观类作为中间层,屏蔽了子系统的具体实现,使得子系统内部的修改不会影响到调用者。

  3. 提高灵活性:由于外观类提供了统一的接口,调用者可以更加灵活地使用子系统,而无需关心子系统的具体实现细节。这有助于增加系统的可扩展性和可维护性。

  4. 易于维护:当子系统内部发生变更时,只需要修改外观类即可,而无需修改所有调用者的代码。这大大降低了系统的维护成本。

5.2 外观模式缺点

  1. 可能违背开闭原则:当需要添加新的子系统功能时,可能需要修改外观类或者增加新的外观类。这在一定程度上违背了开闭原则(即对扩展开放,对修改封闭),可能导致系统的稳定性和可维护性受到影响。

  2. 可能增加不必要的复杂性:在某些情况下,如果子系统本身就很简单或者调用者需要直接访问子系统的某些功能,引入外观模式可能会增加不必要的复杂性。

5.3 适用环境

在以下情况下可以使用外观模式:


  1. 当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。

  2. 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。

  3. 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

5.4 模式拓展

不要试图通过外观类为子系统增加新行为


不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。


外观模式与迪米特法则


外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。


抽象外观类的引入


外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。

06.外观代理总结

6.1 总结一下学习

01.外观模式基础


外观模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,外观模式被引入。


定义是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。更多内容


主要解决的问题


  1. 降低客户端与复杂子系统之间的耦合度。

  2. 简化客户端对复杂系统的操作,隐藏内部实现细节。


02.外观模式实现


假设有一个电脑系统,包含了多个子系统,如音乐功能、视频功能和联网功能。可以打开或者关闭某功能。


实现方式


  1. 创建外观类:定义一个类(外观),作为客户端与子系统之间的中介。提供 Facade 接口,抽象出通用方法打开和关闭。

  2. 封装子系统操作:外观类将复杂的子系统操作封装成简单的方法。三个子系统类(Subsystem):音乐功能、视频功能和联网功能


比如该案例中:


  1. 针对音乐,视频,联网抽象出通用功能,定义成接口【打开和关闭】。充分体现出面向对象中抽象的设计思想!

  2. 针对音乐,视频,联网各个子系统之间的交互,将他们的逻辑封装到外观类中,充分体现出封装的原则!


03.外观实例演示


有个需求:我们知道在 UI 开发中,可以绘制很多图像。比如可以绘制圆形,绘制矩形,绘制椭圆形,绘制……来达到绘制显示的效果。更多内容


05.外观模式分析


外观模式优点:1.简化接口;2.降低耦合;3.提高灵活性;4.方便维护


外观模式缺点:1.当添加新的子类系统,可能需要修改外观类,或者破坏开闭原则;


使用建议:建议 1 不要通过外观类给子类系统加入新的行为。

6.2 更多内容推荐


23 种设计模式


6.3 更多内容


发布于: 刚刚阅读数: 5
用户头像

杨充

关注

还未添加个人签名 2018-07-30 加入

还未添加个人简介

评论

发布
暂无评论
09.外观模式设计思想_杨充_InfoQ写作社区