设计模式之禅——门面模式

article/2025/8/22 15:35:33

门面模式【Facade Pattern】也叫外观模式,是一种比较常用的封装模式,其定义如下:

【要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更容易使用】

门面模式注重“统一的对象”,也就是提供了一个访问子系统的接口,除了这个接口不允许有任何访问子系统的行为发生。

门面模式的系统类图如下:

这里写图片描述

类图就是这么简单,但是意义其实很复杂

Subsystem Classes 是所有子系统所有类的简称,它可能代表一个类,也可能代表几十个对象的集合。不管多少对象,我们都将他们化为子系统的范畴,结构如图:

这里写图片描述

【不管子系统有多麻烦,外部只能通过这个【Facade——门面对象】来进行通信】

一般情况下,Facade会将所有从客户端发来的请求委派到相应的子系统去,也就是说该角色没有实际的 业务逻辑,是一个委托类。

下面是门面模式的通用源码

//子系统源代码
public class ClassA{public void doSomethingA(){//业务逻辑}
}
public class ClassB{public void doSomethingB(){//业务逻辑}
}
public class ClassC{public void doSomethingC(){//业务逻辑}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
//门面对象
public class Facade{//被委托的对象private ClassA a = new ClassA();private ClassB b = new ClassB();private ClassC c = new ClassC();//提供给外部访问的方法public void methodA(){this.a.doSomethingA();}public void methodB(){this.b.doSomethingB();}public void methodC(){this.c.doSomethingC();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下面用一个例子来看一下具体的门面模式

例子:【我要投递信件】

我们都写过纸质的信件,比如给女朋友写情书什么的。写信的过程大家应该都记得——先写信的内容,然后写信封,在把信放到信封里,封好,投递到信箱中进行投递。虽然简单,但是这四个步骤都是不可或缺的!

首先我们看如果不使用门面模式应该是怎样实现的

public interface ILetterProcess {//首先要写信的内容public void writeContext(String context);//其次写信封public void fillEnvelope(String address);//然后邮递public void letterInotoEnvolope();//然后邮递public void sendLetter();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
public class LetterProcessImpl implements ILetterProcess {@Overridepublic void writeContext(String context) {System.out.println("填写信的内容... " + context);}@Overridepublic void fillEnvelope(String address) {System.out.println("填写收信人的姓名和地址..." + address);}@Overridepublic void letterInotoEnvolope() {System.out.println("把信放到信封中...");}@Overridepublic void sendLetter() {System.out.println("邮递信件...");}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
public class Client {public static void main(String[] args) {ILetterProcess letterProcess = new LetterProcessImpl();letterProcess.writeContext("Hello, It's me, do you know Who I am? I'm your old lover.");letterProcess.fillEnvelope("Happy Road No. 666, God Province, Heaven");                                                 letterProcess.letterInotoEnvolope();letterProcess.sendLetter();}
}
Output:
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
把信放到信封中...
邮递信件...*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

上面的代码与高内聚的要求相差甚远,更不说迪米特原则和接口隔离原则了。

怎么办呢?

邮局出了新的业务,你告诉我信的内容和地址,其余的我帮你搞定。

加了一个邮局的类

public class ModenPostOffice {//这就是门面对象private ILetterProcess letterProcess = new LetterProcessImpl();public void sendLetter(String context, String address){letterProcess.writeContext(context);letterProcess.fillEnvelope(address);letterProcess.letterInotoEnvolope();letterProcess.sendLetter();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

修改场景类

public class Client {public static void main(String[] args) {ModenPostOffice modenPostOffice = new ModenPostOffice();String context = "Hello, It's me, do you know Who I am? I'm your old lover.";String address = "Happy Road No. 666, God Province, Heaven";modenPostOffice.sendLetter(context, address);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
//Output
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
把信放到信封中...
邮递信件...
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下面我们要通过一个要求来看一下门面模式的优点:

要求:【新建发送之前请先检查信件是否安全】

//增加了检查信件的Police类
public class Police {public void checkletter(ILetterProcess letterProcess){System.out.println(letterProcess + " 信件已经被检查过了...");}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
//修改ModenPostOffice
public class ModenPostOffice {//这就是门面对象private ILetterProcess letterProcess = new LetterProcessImpl();private Police letterPolice = new Police();public void sendLetter(String context, String address){letterProcess.writeContext(context);letterProcess.fillEnvelope(address);letterPolice.checkletter(letterProcess);letterProcess.letterInotoEnvolope();letterProcess.sendLetter();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

场景类完全一样

//Output
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
com.sdkd.LetterProcessImpl@74a14482 信件已经被检查过了...
把信放到信封中...
邮递信件... 
*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到这个新的要求对客户是透明的,他什么都不用管,只是负责告诉邮局内容和地址就可以了。

不改变子系统对外暴露的接口 、方法,只改变内部的处理逻辑,其他兄弟模块的调用产生了想要得到结果,这确实是一个非常好的设计。这就是门面模式。

最后的UML图如下,层次模块很明显

这里写图片描述

门面模式的优点:

1、减少系统的相互依赖 
2、提供了灵活性 
3、提供了安全性

门面模式的缺点:

门面模式不符合开闭原则,一旦出错风险很大。

门面模式的使用场景:

1、为一个复杂的模块或子系统提供一个供外界访问的接口 
2、子系统相对独立,对外界来说访问只要暗箱操作就可以 
3、预防低水平人员带来的风险扩散。


http://chatgpt.dhexx.cn/article/NtVfvgkv.shtml

相关文章

设计模式之禅读后感

过早优化是万恶之源——Unix编程思想 让正确的程序更快,要比让快速的程序正确容易得多。 文章目录 前言六大设计原则*单一职责原则**里氏替换原则**依赖倒置原则**接口隔离原则**迪米特法则**开闭原则* 二十三种设计模式创建型模式*单例模式**工厂方法模式**抽象工厂…

设计模式之禅笔记

设计模式PK 创建类模式PK 工厂方法模式 VS 建造者模式 工厂方法模式注重的是整体对象的创建方法。建造者模式注重的是部件构建的过程。 工厂方法模式的对象粒度较粗,建造者模式的产品对象粒度较细。 抽象工厂模式 VS 建造者模式 抽象工厂模式也是注重产品的整…

《设计模式之禅》(第2版)

第一部分 大旗不挥 谁敢冲锋 —— 6大设计原则全新解读 第1章 单一职责原则 单一职责原则,Single Responsibility Principle,简称SRP,有且只有一个原因引起类/接口的变更;即一个接口/类只有一个职责,只负责一件事…

设计模式之禅《一》 大旗不挥,谁敢冲锋 ——6大设计原则

设计模式之禅《一》大旗不挥,谁敢冲锋 ——6大设计原则 《一》 六大原则 一:单一职责原则 1、单一职责原则最难划分的就是职责 2、有两个可以变化的原因放到了一个接口中,这就为以后的变化带来了风险。 3、对于单一职责原则,…

设计模式之禅(六大设计原则)

1.单一职责原则(Single Responsibility Principle) 也就是职责划分要明确,单一职责原则提出了一个编写程序的标准,用“职责”或者“变化原因”来衡量接口或者类设计的是否优良,但是“职责”或者“变化原因”都是不可度量的,因项目…

什么是ASCII码

ASCII码英文全称America Standard Code for Information Interchange,中文意思:美国信息交换标准码。它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。适用于所有拉丁文字字母,ASCII码有7位码和8位…

最全ASCii 码表和说明

A的ASCII码是65,a的ASCII码是97。 ASCII码表中,小写字母排在大写字母的后面,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应的小写字母的ASCII码数值就算出来了,是大写字母的ASCII码数…

ASCII码

字符编码即ASCII码(American Standard Code for Information Interchange,美国信息交换标准码,国际通用的计算机内的字符数字的二进制编码),它是7位二进制编码,总共有128个符号,包括英文26个大写字母&#…

什么叫ASCII码

一个字符A,以 字符和整型都可以输出。因为字符A也是以二进制存储,这个二进制对应一个整数 那究竟什么是ASCII码? ASCII不是一个值,而是一种规定。 ASCII规定了不同字符是使用哪个整数值表示 它规定: A --65 B --…

关于ASCII码的转换

目录 ASCII码表ASCII码与字符之间的转换 ASCII码表 ASCII码与字符之间的转换 python中chr()和ord()两个函数可以实现ASCII码与字符之间的转换, 两者之间的关系 转换举例 stringbsuahisas num_list[ord(i) for i in string] str_list[chr(i) for i in num_list] p…

ASCII码介绍

ASCII码 概念 ASCII(American Standard Code for Information Interchange)的缩写(美国标准信息交换代码),已被国际标准化组织ISO采纳,作为国际通用的信息交换标准代码。 诞生背景 计算机对数据的识别、运算和存储都建立在二进制…

ASCII编码

ASCII编码 ASCII编码的概念对控制字符的解释详细说明 ASCII编码的概念 计算机是以二进制的形式来存储数据的,它只认识 0 和 1 两个数字,我们在屏幕上看到的文字,在存储之前都被转换成了二进制(0和1序列),在…

ascii码a和A为什么差32而不是26

ascii码a和A为什么差32而不是26? A的ASCII码是65,a的ASCII码是97; ASCII码表中,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应的小写字母的ASCII码数值就算出来了,是大写字…

ASCII码详解

ASCII简介 ASCII 码使用指定的 7 位或 8 位二进制数组合来表示 128 或 256 种可能的字符。标准 ASCII 码也叫基础ASCII码,使用 7 位二进制数来表示所有的大写和小写字母,数字 0 到 9、标点符号, 以及在美式英语中使用的特殊控制字符。其中&a…

a到z的ascii码值是多少_a和A对应的ASCII码数值分别是多少啊?

展开全部 A的ASCII码是65,a的ASCII码是97。 ASCII码表中,小写字母32313133353236313431303231363533e78988e69d8331333366303066排在大写字母的后面,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应…

输出ASCII码

输出字符的ASCII码 从键盘输入一个字符&#xff0c;按规定格式输出这个字符及它的ASCII码。例如&#xff1a; 输入 A 输出 “The ASCII of A is 65”.//输出的数值在双引号以内// 代码&#xff1a; ​ #include <stdio.h>int main() {char a;scanf("…

ascii码中的A的代码是什么?

ASCII&#xff08;American Standard Code for Information Interchange&#xff0c;美国标准信息交换代码&#xff09;是基于拉丁字母的一套电脑编码系统&#xff0c;主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统&#xff0c;并等同于国际标准ISO/IEC…

system函数阻塞问题

system()函数是阻塞方式进行的&#xff0c;他会新建一个进程! system代码执行完毕才继续执行&#xff01; 注意一点&#xff0c;如下的命令&#xff1a; #include <bits/stdc.h> #include <windows.h> using namespace std; int main() {std::cout << "…

Linux system函数的执行命令并获取状态

在linux中&#xff0c;可以通过调用system函数执行linux命令&#xff0c;但是如何获取执行命令的结果状态呢&#xff0c;也就是是否执行成功。 #include <stdio.h> #include <stdlib.h>int main() {int ret -1;ret system("cat /proc/mounts | grep sda"…

system函数常见用法

system函数 1.用来执行windows常用命令 我们知道 C语言是没有自己的窗口的&#xff0c;比如我们用printf函数在黑框上输出Hello World是其实是调用了windows的DOS交互窗口。 我们在C语言程序中用system可以给操作系统发送指定&#xff0c;其作用与直接在DOS窗口发送指令进行交…