结构型模式:⑤外观模式(Facade Pattern)
核心思想
为复杂子系统提供一个统一的高层接口,隐藏子系统内部的复杂逻辑、依赖关系和调用顺序,使客户端只需调用该接口即可完成复杂操作,无需关心子系统内部的细节。
核心本质
封装复杂性 + 统一入口,通过 “外观类(或结构体)” 协调子系统中多个组件的交互,降低客户端与子系统的耦合度,同时遵循 “最少知识原则”(客户端只需与外观交互,无需了解子系统内部组件)。
典型场景
比如 “家庭影院”:子系统包含投影仪、音响、播放器、灯光等组件,播放电影需要按 “关闭灯光→打开投影仪→打开音响→启动播放器” 的顺序操作;关闭时则相反。外观模式会封装一个 “家庭影院控制器”(外观),客户端只需调用 “播放电影”“关闭影院” 两个接口,无需手动操作每个组件。
C语言编写
场景示例
子系统:投影仪(Projector)、音响(Audio)、播放器(Player)、灯光(Light);外观:家庭影院控制器(HomeTheaterFacade);客户端通过外观的 watch_movie/end_movie 接口,一键完成播放 / 关闭操作。
关键要点
1.子系统独立性:子系统组件(投影仪、音响等)是独立的,拥有自己的接口,可单独使用(如单独打开投影仪),不依赖外观。
2.外观组合子系统:外观结构体通过成员指针持有所有子系统组件的引用,是协调子系统的核心。
3.统一高层接口:外观提供 watch_movie/end_movie 两个简单接口,内部封装了子系统的复杂调用顺序(如播放电影需 6 步操作),客户端无需关心细节。
4.协调逻辑封装:外观负责子系统的调用顺序和依赖关系(如先关灯光再开投影仪),修改逻辑时只需改外观,无需改客户端。
5.解耦客户端与子系统:客户端仅依赖外观接口,不直接操作子系统组件,降低了耦合度(如更换音响品牌,只需修改外观中音响的创建逻辑,客户端无感知)。
6.内存管理:外观的 destroy 方法统一释放所有子系统组件,避免客户端手动管理多个子系统的内存。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// -------------------------- 1. 子系统组件(Subsystem):独立功能模块 --------------------------
// 子系统1:投影仪
typedef struct Projector {
void (*turn_on)(struct Projector* self);
void (*turn_off)(struct Projector* self);
char name[32];
} Projector;
void projector_turn_on(Projector* self) {
printf("[%s] 启动,切换到电影模式\n", self->name);
}
void projector_turn_off(Projector* self) {
printf("[%s] 关闭\n", self->name);
}
Projector* create_projector(const char* name) {
Projector* p = (Projector*)malloc(sizeof(Projector));
strncpy(p->name, name, sizeof(p->name));
p->turn_on = projector_turn_on;
p->turn_off = projector_turn_off;
return p;
}
// 子系统2:音响
typedef struct Audio {
void (*turn_on)(struct Audio* self);
void (*turn_off)(struct Audio* self);
void (*adjust_volume)(struct Audio* self, int volume);
char name[32];
} Audio;
void audio_turn_on(Audio* self) {
printf("[%s] 启动\n", self->name);
}
void audio_turn_off(Audio* self) {
printf("[%s] 关闭\n", self->name);
}
void audio_adjust_volume(Audio* self, int volume) {
printf("[%s] 音量调整到:%d\n", self->name, volume);
}
Audio* create_audio(const char* name) {
Audio* a = (Audio*)malloc(sizeof(Audio));
strncpy(a->name, name, sizeof(a->name));
a->turn_on = audio_turn_on;
a->turn_off = audio_turn_off;
a->adjust_volume = audio_adjust_volume;
return a;
}
// 子系统3:播放器
typedef struct Player {
void (*turn_on)(struct Player* self);
void (*turn_off)(struct Player* self);
void (*play)(struct Player* self, const char* movie);
char name[32];
} Player;
void player_turn_on(Player* self) {
printf("[%s] 启动\n", self->name);
}
void player_turn_off(Player* self) {
printf("[%s] 关闭\n", self->name);
}
void player_play(Player* self, const char* movie) {
printf("[%s] 播放电影:《%s》\n", self->name, movie);
}
Player* create_player(const char* name) {
Player* p = (Player*)malloc(sizeof(Player));
strncpy(p->name, name, sizeof(p->name));
p->turn_on = player_turn_on;
p->turn_off = player_turn_off;
p->play = player_play;
return p;
}
// 子系统4:灯光
typedef struct Light {
void (*turn_on)(struct Light* self);
void (*turn_off)(struct Light* self);
char name[32];
} Light;
void light_turn_on(Light* self) {
printf("[%s] 打开\n", self->name);
}
void light_turn_off(Light* self) {
printf("[%s] 关闭(营造观影氛围)\n", self->name);
}
Light* create_light(const char* name) {
Light* l = (Light*)malloc(sizeof(Light));
strncpy(l->name, name, sizeof(l->name));
l->turn_on = light_turn_on;
l->turn_off = light_turn_off;
return l;
}
// -------------------------- 2. 外观(Facade):家庭影院控制器 --------------------------
typedef struct HomeTheaterFacade {
// 组合子系统组件(核心:外观持有子系统引用)
Projector* projector;
Audio* audio;
Player* player;
Light* light;
// 统一接口:客户端调用的高层方法
void (*watch_movie)(struct HomeTheaterFacade* self, const char* movie);
void (*end_movie)(struct HomeTheaterFacade* self);
void (*destroy)(struct HomeTheaterFacade* self);
} HomeTheaterFacade;
// 外观方法1:播放电影(协调子系统调用顺序)
void home_theater_watch_movie(HomeTheaterFacade* self, const char* movie) {
printf("\n=== 准备播放电影 ===");
self->light->turn_off(self->light); // 1. 关闭灯光
self->projector->turn_on(self->projector); // 2. 打开投影仪
self->audio->turn_on(self->audio); // 3. 打开音响
self->audio->adjust_volume(self->audio, 80); // 4. 调整音量
self->player->turn_on(self->player); // 5. 打开播放器
self->player->play(self->player, movie); // 6. 播放电影
printf("=== 电影播放中 ===\n");
}
// 外观方法2:结束电影(反向协调子系统关闭顺序)
void home_theater_end_movie(HomeTheaterFacade* self) {
printf("\n=== 准备关闭影院 ===");
self->player->turn_off(self->player); // 1. 关闭播放器
self->audio->turn_off(self->audio); // 2. 关闭音响
self->projector->turn_off(self->projector); // 3. 关闭投影仪
self->light->turn_on(self->light); // 4. 打开灯光
printf("=== 影院已关闭 ===\n");
}
// 外观销毁:释放所有子系统组件
void home_theater_destroy(HomeTheaterFacade* self) {
if (self != NULL) {
free(self->projector);
free(self->audio);
free(self->player);
free(self->light);
free(self);
}
}
// 创建外观实例(初始化子系统组件)
HomeTheaterFacade* create_home_theater_facade() {
HomeTheaterFacade* facade = (HomeTheaterFacade*)malloc(sizeof(HomeTheaterFacade));
// 初始化子系统组件
facade->projector = create_projector("索尼投影仪");
facade->audio = create_audio("BOSE音响");
facade->player = create_player("蓝光播放器");
facade->light = create_light("客厅灯光");
// 绑定外观接口
facade->watch_movie = home_theater_watch_movie;
facade->end_movie = home_theater_end_movie;
facade->destroy = home_theater_destroy;
return facade;
}
// -------------------------- 测试代码(客户端) --------------------------
int main() {
// 1. 创建外观实例(客户端仅与外观交互)
HomeTheaterFacade* theater = create_home_theater_facade();
// 2. 客户端一键播放电影(无需关心子系统细节)
theater->watch_movie(theater, "星际穿越");
// 3. 客户端一键关闭影院
theater->end_movie(theater);
// 4. 释放资源
theater->destroy(theater);
return 0;
}
C++语言实现
同 C 语言:子系统(Projector/Audio/Player/Light)+ 外观(HomeTheaterFacade),客户端一键操作家庭影院。通过 “独立类实现子系统组件”“外观类组合子系统实例”,利用类的封装性隐藏子系统细节,提供简洁的高层接口,且通过智能指针自动管理内存。
关键要点
1.子系统封装:子系统组件(Projector/Audio 等)是独立类,封装自身功能,对外提供清晰接口,不依赖外观。
2.外观组合子系统:外观类通过 std::unique_ptr 持有子系统实例,智能指针自动管理内存,无需手动释放。
3.高层接口简洁:外观提供 WatchMovie/EndMovie 两个核心接口,客户端调用时无需知道内部调用顺序(如先关灯光还是先开投影仪)。
4.逻辑集中管理:子系统的调用顺序、依赖关系集中在外观中,修改时只需调整外观代码(如新增 “打开幕布” 组件,只需在外观中添加调用),符合 “开闭原则”。
5.低耦合:客户端仅依赖 HomeTheaterFacade 类,与子系统组件完全解耦(如更换投影仪品牌,只需修改外观中 Projector 的创建逻辑,客户端无感知)。
6.类型安全:C++ 的类和成员函数提供编译期类型检查,避免 C 语言中函数指针绑定错误或类型转换风险。
#include <iostream>
#include <string>
#include <memory> // 智能指针(自动管理内存)
// -------------------------- 1. 子系统组件(Subsystem):独立类 --------------------------
// 子系统1:投影仪
class Projector {
public:
explicit Projector(std::string name) : name_(std::move(name)) {}
void TurnOn() const {
std::cout << "[" << name_ << "] 启动,切换到电影模式" << std::endl;
}
void TurnOff() const {
std::cout << "[" << name_ << "] 关闭" << std::endl;
}
private:
std::string name_;
};
// 子系统2:音响
class Audio {
public:
explicit Audio(std::string name) : name_(std::move(name)) {}
void TurnOn() const {
std::cout << "[" << name_ << "] 启动" << std::endl;
}
void TurnOff() const {
std::cout << "[" << name_ << "] 关闭" << std::endl;
}
void AdjustVolume(int volume) const {
std::cout << "[" << name_ << "] 音量调整到:" << volume << std::endl;
}
private:
std::string name_;
};
// 子系统3:播放器
class Player {
public:
explicit Player(std::string name) : name_(std::move(name)) {}
void TurnOn() const {
std::cout << "[" << name_ << "] 启动" << std::endl;
}
void TurnOff() const {
std::cout << "[" << name_ << "] 关闭" << std::endl;
}
void Play(const std::string& movie) const {
std::cout << "[" << name_ << "] 播放电影:《" << movie << "》" << std::endl;
}
private:
std::string name_;
};
// 子系统4:灯光
class Light {
public:
explicit Light(std::string name) : name_(std::move(name)) {}
void TurnOn() const {
std::cout << "[" << name_ << "] 打开" << std::endl;
}
void TurnOff() const {
std::cout << "[" << name_ << "] 关闭(营造观影氛围)" << std::endl;
}
private:
std::string name_;
};
// -------------------------- 2. 外观(Facade):家庭影院控制器 --------------------------
class HomeTheaterFacade {
public:
// 构造函数:初始化子系统组件(智能指针自动管理内存)
HomeTheaterFacade()
: projector_(std::make_unique<Projector>("索尼投影仪")),
audio_(std::make_unique<Audio>("BOSE音响")),
player_(std::make_unique<Player>("蓝光播放器")),
light_(std::make_unique<Light>("客厅灯光")) {}
// 统一高层接口:播放电影
void WatchMovie(const std::string& movie) const {
std::cout << "\n=== 准备播放电影 ===" << std::endl;
light_->TurnOff(); // 1. 关闭灯光
projector_->TurnOn(); // 2. 打开投影仪
audio_->TurnOn(); // 3. 打开音响
audio_->AdjustVolume(80); // 4. 调整音量
player_->TurnOn(); // 5. 打开播放器
player_->Play(movie); // 6. 播放电影
std::cout << "=== 电影播放中 ===\n" << std::endl;
}
// 统一高层接口:结束电影
void EndMovie() const {
std::cout << "=== 准备关闭影院 ===" << std::endl;
player_->TurnOff(); // 1. 关闭播放器
audio_->TurnOff(); // 2. 关闭音响
projector_->TurnOff(); // 3. 关闭投影仪
light_->TurnOn(); // 4. 打开灯光
std::cout << "=== 影院已关闭 ===\n" << std::endl;
}
private:
// 组合子系统组件(智能指针自动释放内存)
std::unique_ptr<Projector> projector_;
std::unique_ptr<Audio> audio_;
std::unique_ptr<Player> player_;
std::unique_ptr<Light> light_;
};
// -------------------------- 测试代码(客户端) --------------------------
int main() {
// 1. 创建外观实例(客户端仅与外观交互)
HomeTheaterFacade theater;
// 2. 客户端一键播放电影(无需关心子系统细节)
theater.WatchMovie("星际穿越");
// 3. 客户端一键关闭影院
theater.EndMovie();
return 0; // 智能指针自动销毁所有子系统组件,无需手动释放
}
外观模式核心总结(C vs C++)

设计原则
1.最少知识原则:客户端只需了解外观,无需了解子系统内部组件;
2.单一职责原则:外观负责协调子系统,子系统负责自身功能,职责清晰;
3.开闭原则:扩展子系统时(如新增组件),只需修改外观,无需修改客户端和现有子系统。
2558

被折叠的 条评论
为什么被折叠?



