Java二十三种设计模式-外观模式(9/23)

news2024/11/27 13:41:09

外观模式:简化复杂系统的统一接口

引言

外观模式(Facade Pattern)是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口。外观模式定义了一个可以与复杂子系统交互的简化接口,使得子系统更加易于使用。

基础知识,java设计模式总体来说设计模式分为三大类:

(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

第一部分:外观模式概述

1.1 定义与用途

外观模式的基本定义

外观模式(Facade Pattern)是一种常用的结构型设计模式,其核心目的是为一个复杂的子系统提供一个简化的统一接口。通过外观模式,客户端可以访问一个复杂的类系统,而无需了解该系统内部的复杂性。

解释为何需要外观模式

  • 简化接口:在大型软件系统中,尤其是当系统由多个类和组件构成时,客户端代码可能需要与这些复杂的类交互。外观模式通过提供一个简化的接口,简化了客户端与这些类的交互。
  • 降低耦合度:外观模式降低了客户端与复杂子系统的耦合度,客户端不依赖于子系统的具体实现,只依赖于外观对象。
  • 易于维护和扩展:当子系统需要修改或扩展时,只要接口保持不变,客户端代码就不需要修改,从而提高了系统的可维护性和可扩展性。

1.2 外观模式的组成

外观(Facade)

  • 定义:外观是一个接口,它提供了一组特定的方法,用于访问子系统中的复杂功能。
  • 角色:作为客户端与子系统交互的中介,外观对象将客户端的请求委托给子系统中的相应对象。

子系统(Subsystem)

  • 定义:子系统是一系列类和接口的集合,它们实现了特定的功能。
  • 角色:子系统包含了业务逻辑的具体实现,外观对象通过子系统来完成请求的处理。

客户端(Client)

  • 角色:客户端使用外观对象来访问子系统的功能,客户端不直接与子系统交互。

外观模式通过引入外观对象,将客户端与复杂的子系统解耦,使得客户端可以更加容易地使用子系统的功能。在下一部分中,我们将通过Java代码示例来展示外观模式的具体实现。

第二部分:外观模式的实现

2.1 Java实现示例

以下是使用Java语言实现外观模式的代码示例。假设我们有一个复杂的家庭影院系统,包括多个组件如投影仪、音响和屏幕。

// 子系统接口
interface TheaterControl {
    void on();
    void off();
    void setVolume(int volume);
}

// 具体子系统:投影仪
class Projector implements TheaterControl {
    public void on() { System.out.println("Projector on."); }
    public void off() { System.out.println("Projector off."); }
    // 投影仪没有音量设置
}

// 具体子系统:音响
class StereoSystem implements TheaterControl {
    public void on() { System.out.println("Stereo on."); }
    public void off() { System.out.println("Stereo off."); }
    public void setVolume(int volume) {
        System.out.println("Stereo volume set to " + volume);
    }
}

// 具体子系统:屏幕
class Screen implements TheaterControl {
    public void on() { System.out.println("Screen on."); }
    public void off() { System.out.println("Screen off."); }
    // 屏幕没有音量设置
}

// 外观
class HomeTheaterFacade {
    private TheaterControl projector;
    private TheaterControl stereoSystem;
    private TheaterControl screen;

    public HomeTheaterFacade() {
        this.projector = new Projector();
        this.stereoSystem = new StereoSystem();
        this.screen = new Screen();
    }

    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a " + movie + "!");
        turnOn();
        setVolume(5);
        projector.on();
        screen.on();
    }

    private void turnOn() {
        projector.on();
        stereoSystem.on();
        screen.on();
    }

    private void setVolume(int volume) {
        stereoSystem.setVolume(volume);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        HomeTheaterFacade homeTheater = new HomeTheaterFacade();
        homeTheater.watchMovie("Java Design Patterns");
    }
}

2.2 外观模式中的角色和职责

外观(Facade)

  • 职责:为复杂的子系统提供一个简化的接口。外观对象通常包含多个子系统对象的引用,并将客户端的请求委托给相应的子系统对象。
  • 实现:外观类通常包含子系统的引用,并提供一系列方法,这些方法将复杂的操作封装成简单的步骤。

子系统(Subsystem)

  • 职责:实现特定的功能,子系统可以独立于外观和其他子系统运行。
  • 实现:每个子系统都是一个类,实现特定的功能,如上述示例中的ProjectorStereoSystemScreen

客户端(Client)

  • 职责:使用外观对象来访问子系统的功能,客户端不直接与子系统交互。
  • 实现:客户端通过外观对象的方法来执行操作,如上述示例中的Client类。

相互作用

  • 客户端调用:客户端调用外观对象的方法。
  • 外观委托:外观对象将请求委托给一个或多个子系统。
  • 子系统执行:子系统执行具体的操作并返回结果(如果有的话)。

外观模式通过引入外观对象,简化了客户端与复杂子系统的交互,降低了系统间的耦合度,提高了系统的可维护性和可扩展性。在下一部分中,我们将探讨外观模式的使用场景。

 

第三部分:外观模式的使用场景

3.1 简化复杂系统的访问

在软件开发中,经常会遇到一些复杂的系统,这些系统可能包含多个组件和子系统,每个部分都有其特定的功能和接口。对于客户端来说,直接与这些复杂的系统交互可能会非常困难和繁琐。

外观模式的应用:

  • 统一接口:外观模式提供一个统一的高层接口,使得客户端可以通过这个简化的接口与复杂系统交互,而无需了解内部的复杂性。
  • 简化客户端逻辑:通过外观模式,客户端的代码可以更加简洁和易于理解,因为客户端只需要与外观对象交互,而不是直接与复杂的子系统交互。
  • 易于使用:外观模式隐藏了复杂的实现细节,使得即使是不熟悉系统内部结构的用户也能容易地使用系统。

应用实例:

  • 操作系统的命令行界面:提供了一个简化的接口来执行复杂的系统命令。
  • 智能家居控制系统:通过一个简单的界面控制家中的多个智能设备,如灯光、温度、安全系统等。

3.2 降低系统间的耦合度

在大型软件项目中,系统通常由多个模块或服务组成,这些模块之间可能存在紧密的耦合关系。耦合度过高会导致系统难以维护和扩展。

外观模式的优势:

  • 解耦系统组件:外观模式通过引入一个外观层,将客户端与子系统的直接依赖关系转换为对外观的依赖,从而降低了系统间的耦合度。
  • 提高模块化:通过降低模块间的直接依赖,系统可以更加模块化,每个模块可以独立地开发和测试。
  • 易于扩展和维护:当系统需要扩展或修改时,只要外观接口保持不变,就不需要修改依赖于这个接口的客户端代码。

应用实例:

  • 支付系统集成:在电子商务平台中,可能需要集成多种支付方式,如信用卡、PayPal、微信支付等。通过外观模式,可以为这些支付方式提供一个统一的接口,降低它们之间的耦合度。
  • 中间件服务:在企业应用中,中间件服务如数据库连接池、消息队列等,可以通过外观模式提供简化的接口,使得应用程序更容易与这些服务交互。

外观模式通过提供一个简化的接口来简化复杂系统的访问,并降低系统间的耦合度。这使得系统更加易于使用、维护和扩展。在下一部分中,我们将讨论外观模式的优点与缺点。

第四部分:外观模式的优点与缺点

4.1 优点

简化接口

  • 统一访问点:为复杂的子系统提供一个简化的统一接口,简化了客户端的交互方式。

降低耦合度

  • 减少依赖:客户端不直接依赖于复杂的子系统,而是通过外观对象进行交互,降低了耦合度。

提高可维护性

  • 易于修改和扩展:当子系统需要修改或扩展时,只要外观接口保持不变,客户端代码不需要修改。

隐藏实现细节

  • 保护子系统:外观模式隐藏了子系统的实现细节,客户端不需要了解内部的复杂逻辑。

4.2 缺点

过度封装

  • 隐藏过度:如果外观对象封装过度,可能会隐藏必要的信息,使得客户端难以使用子系统的全部功能。

更新困难

  • 接口变更:一旦外观对象的接口被广泛使用,对其进行更新或修改可能会变得困难。

性能问题

  • 潜在的性能开销:在某些情况下,外观模式可能会引入额外的性能开销,尤其是在需要频繁调用多个子系统方法时。

第五部分:外观模式与其他模式的比较

5.1 与适配器模式的比较

适配器模式

  • 目的:使不兼容的接口能够一起工作,主要用于接口转换。
  • 实现:通常通过一个适配器类来转换接口。

外观模式

  • 目的:为复杂的子系统提供一个简化的统一接口,主要用于简化客户端与子系统的交互。

对比

  • 使用场景:适配器模式主要用于解决接口不兼容的问题,而外观模式主要用于简化对复杂子系统的访问。

5.2 与代理模式的对比

代理模式

  • 目的:为另一个对象提供一个代替或占位符,以控制对它的访问。
  • 实现:代理对象在客户端和真实对象之间起到中介的作用。

外观模式

  • 目的:为复杂的子系统提供一个简化的统一接口。

对比

  • 控制访问:代理模式主要用于控制对对象的访问,而外观模式主要用于简化对复杂子系统的访问。
  • 使用场景:代理模式适用于需要控制访问权限或延迟初始化的场景,外观模式适用于需要简化对复杂系统操作的场景。

外观模式通过提供一个简化的接口来简化复杂系统的访问,并降低系统间的耦合度。然而,合理使用外观模式并避免其缺点是至关重要的。了解其替代方案和与其他模式的比较可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用外观模式,以达到最佳的设计效果。

第六部分:外观模式的最佳实践和建议

6.1 最佳实践

保持外观的简洁性

  • 单一职责:确保外观类保持简洁,专注于提供一个简化的接口,而不是实现复杂的逻辑。

明确外观的职责

  • 职责分离:外观类应该只负责协调子系统的操作,不包含业务逻辑。

避免过度封装

  • 适度封装:避免隐藏过多的信息和功能,确保客户端能够访问到必要的子系统功能。

提供清晰的文档

  • 文档说明:为外观类提供清晰的文档,说明其提供的功能和使用方法。

考虑线程安全

  • 并发访问:如果外观类可能会被多个线程访问,确保其方法是线程安全的。

灵活使用

  • 适应变化:设计外观类时,考虑未来可能的变化,使其能够灵活适应子系统的扩展和修改。

6.2 避免滥用

避免创建过多的外观类

  • 合理使用:只在确实需要简化复杂系统接口时使用外观模式,避免创建不必要的外观类。

避免过度集中逻辑

  • 逻辑分散:避免将过多的业务逻辑集中在外观类中,这可能会导致外观类变得复杂和难以维护。

避免过度隐藏细节

  • 适度隐藏:适度隐藏实现细节,确保客户端能够访问到必要的功能和信息。

6.3 替代方案

使用依赖注入

  • 依赖注入:通过依赖注入来管理对象的依赖关系,而不是通过外观类来协调子系统。

使用中介者模式

  • 中介者模式:当系统中的对象之间存在复杂的通信时,可以使用中介者模式来简化它们之间的交互。

使用命令模式

  • 命令模式:当需要对操作进行封装和调度时,可以使用命令模式来实现。

使用策略模式

  • 策略模式:当需要根据不同的策略动态改变对象行为时,可以使用策略模式。

使用组合模式

  • 组合模式:当需要表示部分-整体层次结构时,可以使用组合模式。

外观模式是一种有用的设计模式,可以简化复杂系统的访问并降低系统间的耦合度。然而,合理使用外观模式并避免其缺点是至关重要的。了解其替代方案可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用外观模式,以达到最佳的设计效果。

结语

外观模式提供了一种简化复杂系统访问的方法,使得客户端可以更容易地与复杂的子系统交互。通过本文的深入分析,希望读者能够对外观模式有更全面的理解,并在实际开发中做出合理的设计选择。

 相关Java设计模式文章推荐:

Java二十三种设计模式-单例模式(1/23)

Java二十三种设计模式-工厂方法模式(2/23)

Java二十三种设计模式-抽象工厂模式(3/23)

Java二十三种设计模式-建造者模式(4/23)

Java二十三种设计模式-原型模式(5/23)

Java二十三种设计模式-适配器模式(6/23)

Java二十三种设计模式-装饰器模式(7/23)

Java二十三种设计模式-代理模式(8/23)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961917.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

科研绘图系列:R语言GWAS曼哈顿图(Manhattan plot)

介绍 曼哈顿图(Manhattan Plot)是一种常用于展示全基因组关联研究(Genome-Wide Association Study, GWAS)结果的图形。GWAS是一种研究方法,用于识别整个基因组中与特定疾病或性状相关的遗传变异。 特点: 染色体表示:曼哈顿图通常将每个染色体表示为一个水平条,染色体…

Git 基础操作手册:轻松掌握常用命令

Git 操作完全手册:轻松掌握常用命令 引言一、暂存:git add ✏️二、提交:git commit 📝三、拉取、拉取合并 🔄四、推送:git push 🌐五、查看状态:git status 📊六、查看历…

第09课 Scratch入门篇:小鸡啄米-自制积木实现

小鸡啄米-自制积木 故事背景: 在上一章的案例中,实现了小鸡啄米的动画,但是发现太多的重复代码,是我们编程的时候代码泰国繁琐,我们可以使用自制积木,将相同的代码提取出来制作成一个新的积木,在…

ESP32CAM人工智能教学17

ESP32CAM人工智能教学17 内网穿透,视频上云 小智一心想让ESP32Cam视频能发送到云端,这样我们在任何地方,都能查看到家里的摄像头了,甚至能控制摄像头的小车了。 内网穿透的技术原理想要让ESP32Cam把视频发送到云端,就必须要做内网穿透。也就是用户的手机(或电脑),可以…

Windows中如何配置Gradle环境变量?

本篇教程,主要介绍,如何在Windows中配置Gradle7.4环境变量 一、下载安装包 安装包下载;gradle-7.4-all.zip 二、解压安装包

Python基础知识笔记---保留字

保留字,也称关键字,是指被编程语言内部定义并保留使用的标识符。 一、保留字概览 二、保留字用途 1. False:表示布尔值假。 2. None:表示空值或无值。 3. True:表示布尔值真。 4. not:布尔逻辑操作符…

LabVIEW 使用 I/O 服务器

I/O 服务器是共享变量引擎(SVE)插件,用于与不使用NI专有的NI发布-订阅协议(NI-PSP)的设备和应用程序通信。I/O 服务器充当LabVIEW VI中的共享变量与OPC、Modbus或EPICS数据标签之间的桥梁。它们插入SVE中,提…

生成式人工智能最重要的三个神经网络,从谷歌DeepDream、Magenta、到NVIDIA的StyleGAN

神经网络模型(Neural Network Model)是一种受生物大脑启发的机器学习模型,用于模拟人脑的结构和功能。它由大量相互连接的人工神经元(节点)组成,这些神经元按层级结构排列,通常包括输入层、隐藏…

OSI七层网络模型:构建网络通信的基石

在计算机网络领域,OSI(Open Systems Interconnection)七层模型是理解网络通信过程的关键框架。该模型将网络通信过程细分为七个层次,每一层都有其特定的功能和职责,共同协作完成数据从发送端到接收端的传输。接下来&am…

制品库nexus

详见:Sonatype Nexus Repository搭建与使用(详细教程3.70.1)-CSDN博客 注意事项: 1.java8环境使用nexus-3.69.0-02-java8-unix.tar.gz包 2.java11环境使用nexus-3.70.1-02-java11-unix.tar.gz包 3.注意使用制品库/etc/yum.repos.…

leetcode 1596 每位顾客经常订购的商品(postgresql)

需求 表:Customers ---------------------- | Column Name | Type | ---------------------- | customer_id | int | | name | varchar | ---------------------- customer_id 是该表主键 该表包含所有顾客的信息 表:Orders ---------------------- …

LeetCode 144.二叉树的前序遍历 C写法

LeetCode 144.二叉树的前序遍历 思路🧐: 遍历很简单,但是我们需要开空间进行值的存储,结点个数也可以用递归进行统计,开好空间就可以用数组进行值的存储,注意下标要么用全局,要么指针解引用&…

【Canvas与艺术】五色五角大楼

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>五L莫比乌斯五角大楼</title><style type"text/css&qu…

解决国内 github.com 打不开进不去的方法

解决国内 github.com 打不开进不去的方法 修改host文件 电脑的hosts文件在下面这个地址&#xff0c;找到hosts文件 C:\Windows\System32\Drivers\etc 右键点击hosts文件,选择复制,然后粘贴到桌面上。右键点击桌面上的hosts文件,选择“用记事本打开该文件”,hosts 文件中需要写…

VPX电源模块性能检测需要测试哪些指标?

随着技术的不断进步&#xff0c;VPX电源模块已成为军工、通讯等关键行业不可或缺的组成部分。接下来&#xff0c;让我们一起了解VPX电源以及如何检测其性能。 什么是VPX电源&#xff1f; VPX电源是一种军用嵌入式计算机规范下的电源产品&#xff0c;采用了7排引脚阵列高速连接器…

使用Android Studio For Platform阅读调试AOSP源码

上一篇文章中&#xff0c;我们编译了AOSP的源码并刷入自己编译的ROM到Pixel 6设备中。本文我们使用Android官方提供的IDE&#xff08;Android Studio For Platform&#xff09;来打开AOSP源码&#xff0c;并进行debug调试&#xff0c;这样可以方便我们跟踪底层代码的调用流程。…

C# (VS2019 Frameworks) 背景程序组件BackgroundWorker 的基本和使用

前言&#xff1a; C#的应用软件中&#xff0c;经常要考虑到UI的相应和处理的程序&#xff08;尤其占用时间很长的程序&#xff09;之前的相应配合问题。 传统的思路&#xff0c;用线程的控制方法&#xff0c;加原子锁等方法&#xff0c;可是&#xff0c;再怎么搞都没有 windo…

大数据学习之Flink基础(补充)

Flink基础 1、系统时间与事件时间 系统时间&#xff08;处理时间&#xff09; 在Sparksreaming的任务计算时&#xff0c;使用的是系统时间。 假设所用窗口为滚动窗口&#xff0c;大小为5分钟。那么每五分钟&#xff0c;都会对接收的数据进行提交任务. 但是&#xff0c;这里有…

【HadoopShuffle原理剖析】基础篇二

Shuffle原理剖析 Shuffle&#xff0c;是指对Map输出结果进行分区、排序、合并等处理并交给Reduce的过程。分为Map端的操作和Reduce端的操作。 Shuffle过程 Map端的Shuffle Map的输出结果首先被缓存到内存&#xff0c;当缓存区容量到达80%&#xff08;缓冲区默认100MB&#xff…