【声明】本题目来源于卡码网(题目页面 (kamacoder.com))
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
【简介】什么是外观模式
外观模式Facade Pattern , 也被称为“⻔⾯模式”,是⼀种结构型设计模式,外观模式定义了⼀个⾼层接⼝,这个接⼝使得⼦系统更容易使⽤,同时也隐藏了⼦系统的复杂性。
----⻔⾯模式可以将⼦系统关在“⻔⾥”隐藏起来,客户端只需要通过外观接⼝与外观对象进⾏交互,⽽不需要直接和多个⼦系统交互,⽆论⼦系统多么复杂,对于外部来说是隐藏的,这样可以降低系统的耦合度。
举个例⼦,假设你正在编写的⼀个模块⽤来处理⽂件读取、解析、存储,我们可以将这个过程拆成三部分,然后创建⼀个外观类,将⽂件系统操作、数据解析和存储操作封装在外观类中,为客户端提供⼀个简化的接⼝,如果后续需要修改⽂件处理的流程或替换底层⼦系统,也只需在外观类中进⾏调整,不会影响客户端代码。
【基本结构】
外观模式的基本结构⽐较简单,只包括“外观”和“⼦系统类”:
- 外观类:对外提供⼀个统⼀的⾼层次接⼝,使复杂的⼦系统变得更易使⽤。
- ⼦系统类:实现⼦系统的功能,处理外观类指派的任务。
【简易实现步骤】
下⾯使⽤Java代码实现外观模式的通⽤结构:
1. 子系统A
// ⼦系统A
class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operation");
}
}
2. 子系统B
// ⼦系统B
class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operation");
}
}
3. 子系统C
// ⼦系统C
class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operation");
}
}
4. 外观类
// 外观类
class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
this.subsystemC = new SubsystemC();
}
// 外观⽅法,封装了对⼦系统的操作
public void facadeOperation() {
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
5. 客户端代码
// 客户端
public class Main {
public static void main(String[] args) {
// 创建外观对象
Facade facade = new Facade();
// 客户端通过外观类调⽤⼦系统的操作
facade.facadeOperation();
}
}
在上⾯的代码中, Facade 类是外观类,封装了对三个⼦系统SubSystem 的操作。客户端通过调⽤外观类的⽅法来实现对⼦系统的访问,⽽不需要直接调⽤⼦系统的⽅法。
【优缺点和使用场景】
外观模式通过提供⼀个简化的接⼝,隐藏了系统的复杂性,降低了客户端和⼦系统之间的耦合度,客户端不需要了解系统的内部实现细节,也不需要直接和多个⼦系统交互,只需要通过外观接⼝与外观对象进⾏交互。
但是如果需要添加新的⼦系统或修改⼦系统的⾏为,就可能需要修改外观类,这违背了“开闭原则”。
外观模式的应⽤也⼗分普遍,下⾯⼏种情况都使⽤了外观模式来进⾏简化。
- Spring框架是⼀个⼴泛使⽤外观模式的例⼦。Spring框架提供了⼀个⼤量的功能,包括依赖注⼊、⾯向切⾯编程(AOP)、事务管理等。Spring的ApplicationContext 可以看作是外观,隐藏了底层组件的复杂性,使得开发者可以更轻松地使⽤Spring的功能。
- JDBC提供了⼀个⽤于与数据库交互的接⼝。DriverManager 类可以看作是外观,它简化了数据库驱动的加载和连接的过程,隐藏了底层数据库连接的复杂性。
- Android系统的API中也使⽤了外观模式。例如, Activity 类提供了⼀个外观,使得开发者可以更容易地管理应⽤的⽣命周期,⽽⽆需关⼼底层的事件和状态管理。
【编码部分】
1. 题目描述
小明家的电源总开关控制了家里的三个设备:空调、台灯和电视机。每个设备都有独立的开关密码,分别用数字1、2和3表示。即输入1时,空调关闭,输入2时,台灯关闭,输入3时,电视机关闭,当输入为4时,表示要关闭所有设备。请你使用外观模式编写程序来描述电源总开关的操作。
2. 输入描述
第一行是一个整数 N(1 <= N <= 100),表示后面有 N 行输入。接下来的 N 行,每行包含一个数字,表示对应设备的开关操作(1表示关闭空调,2表示关闭台灯,3表示关闭电视机,4表示关闭所有设备)。
3. 输出描述
输出关闭所有设备后的状态,当输入的数字不在1-4范围内时,输出Invalid device code.
4. C++编码实例
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file FacadeMode.hpp
* @brief 外观模式
* @autor 写代码的小恐龙er
* @date 2024/01/11
*/
#include <iostream>
#include <string>
using namespace std;
// 前置声明
// 子系统1 -- 空调
class AirConditioner;
// 子系统2 -- 台灯
class Light;
// 子系统3 -- 电视机
class TV;
// 外观模式的管理类 -- 接口类的派生类
class FacadePowerSwitch;
// 子系统1 -- 空调
class AirConditioner
{
public:
void TurnOff(){
std::cout << "Air Conditioner is turned off." << endl;
}
};
// 子系统1 -- 空调
class Light
{
public:
void TurnOff(){
std::cout << "Desk Lamp is turned off." << endl;
}
};
// 子系统1 -- 空调
class TV
{
public:
void TurnOff(){
std::cout << "Television is turned off." << endl;
}
};
// 外观模式的管理类 -- 接口类的派生类
class FacadePowerSwitch
{
// 成员数据
private:
AirConditioner *_airConditioner;
Light *_light;
TV *_tv;
// 成员函数
public:
// 重载构造函数 和 析构函数
FacadePowerSwitch()
{
_airConditioner = new AirConditioner();
_light = new Light();
_tv = new TV();
}
~FacadePowerSwitch(){
if(_airConditioner != nullptr) {
delete _airConditioner;
_airConditioner = nullptr;
}
if(_light != nullptr) {
delete _light;
_light = nullptr;
}
if(_tv != nullptr) {
delete _tv;
_tv = nullptr;
}
}
// 子系统业务代码
void TurnOffContion(int orderType){
switch(orderType)
{
case 1:
_airConditioner->TurnOff();
break;
case 2:
_light->TurnOff();
break;
case 3:
_tv->TurnOff();
break;
case 4:
std::cout << "All devices are off." << endl;
break;
default:
std::cout << "Invalid device code." << endl;
break;
}
}
};
int main()
{
// 指令值个数
int orderNum = 0;
std::cin >> orderNum;
// 创建外观管理类对象
FacadePowerSwitch *facadePowerSwitch = new FacadePowerSwitch();
for(int i = 0; i < orderNum; i++)
{
// 指令值
int orderType = 0;
std::cin >> orderType;
//并调用业务函数
facadePowerSwitch->TurnOffContion(orderType);
}
delete facadePowerSwitch;
facadePowerSwitch = nullptr;
return 0;
}
......
To be continued.