理解和实现 C# 中的外观模式






4.89/5 (38投票s)
本文讨论了外观模式。何时使用此模式才有用?本文还介绍了一种实现外观模式的初步方法。
引言
本文讨论了外观模式。何时使用此模式才有用?本文还介绍了一种实现外观模式的初步方法。
背景
在我们的应用程序中,有时我们需要使用一系列对象来执行某些任务。例如,如果我们正在为通用遥控器编写软件,并且我想关闭所有设备,那么我有几个选择。首先,我可以手动选择每个设备并逐个关闭它们。这是一种相当粗糙的方法,所以为什么不在遥控器内部自动执行此操作呢?这样我就可以有一个按钮来关闭所有设备。现在要关闭所有设备,我只需要按下这个按钮。这个遥控器的按钮按下命令现在将与所有设备控制器通信并关闭它们。
现在,如果我需要在晚上 12 点自动执行类似的功能。现在,这个基于计时器的事件也将与所有设备通信并停止它们。因此,这里的问题是,在所有需要此功能的场景中,我都需要与这些对象通信。
在设计此解决方案时,还有另一种方法。为什么不创建一个对象的职责是停止所有设备呢?现在,每当需要停止所有设备时,我只需要调用这个对象。这正是外观模式背后的理念。GoF 将外观模式定义为“为子系统中的一组接口提供一个统一的接口。外观定义了一个更高级别的接口,使子系统更易于使用。”
可视化此模式

这里需要注意的重要一点是,外观对象只是以更简单的方式提供了一组功能。它没有改变子系统的接口。子系统类仍然可以被系统的其他部分访问。外观将在一个位置提供一组功能。
使用代码
为了说明外观模式,让我们尝试看一个小例子。让我们尝试实现一个假设的外观对象来处理一些 Windows Phone 控制器对象。首先让我定义问题。
每天早上我去慢跑时,我必须在我的 Windows Phone 设备中进行以下更改
- 关闭 Wifi
- 打开移动数据
- 打开 GPS
- 打开音乐
- 启动运动追踪器
从慢跑回来后,我需要做以下事情
- 在 Twitter 和 Facebook 上分享运动追踪器统计信息
- 停止运动追踪器
- 关闭音乐
- 关闭 GPS
- 关闭移动数据
- 打开 Wifi
所有这些现在都是手动完成的。因此,为了模拟行为,让我们首先实现子系统,即虚拟控制器类。
class GPSController
{
bool isSwitchedOn = false;
public bool IsSwitchedOn
{
get
{
return isSwitchedOn;
}
set
{
isSwitchedOn = value;
DisplayStatus();
}
}
private void DisplayStatus()
{
string status = (isSwitchedOn == true) ? "ON" : "OFF";
Console.WriteLine("GPS Switched {0}", status);
}
}
其他控制器,例如 MobileDataController
、MusicController
、WifiController
也以类似的方式实现。
现在模拟应用程序行为。
class SportsTrackerApp
{
public void Start()
{
Console.WriteLine("Sports Tracker App STARTED");
}
public void Stop()
{
Console.WriteLine("Sports Tracker App STOPPED");
}
public void Share()
{
Console.WriteLine("Sports Tracker: Stats shared on twitter and facebook.");
}
}
所以现在我所做的是手动更改所有设置,然后手动启动应用程序。这可以以代码的形式可视化为
static void Main(string[] args)
{
// The phone has been booted up and all the controllers are running
GPSController gps = new GPSController();
MobileDataController data = new MobileDataController();
MusicController zune = new MusicController();
WifiController wifi = new WifiController();
///////////// Going for Jogging /////////////////////
// 1. Turn off the wifi
wifi.IsSwitchedOn = false;
// 2. Switch on the Mobile Data
data.IsSwitchedOn = true;
// 3. Turn on the GPS
gps.IsSwitchedOn = true;
// 4. Turn on the Music
zune.IsSwitchedOn = true;
// 5. Start the Sports-Tracker
SportsTrackerApp app = new SportsTrackerApp();
app.Start();
///////////// Back from Jogging /////////////////////
Console.WriteLine();
// 0. Share Sports tracker stats on twitter and facebook
app.Share();
// 1. Stop the Sports Tracker
app.Stop();
// 2. Turn off the Music
zune.IsSwitchedOn = false;
// 3. Turn off the GPS
gps.IsSwitchedOn = false;
// 4. Turn off the Mobile Data
data.IsSwitchedOn = false;
// 5. Turn on the wifi
wifi.IsSwitchedOn = true;
}
注意:所有这些都是为了模拟我的 Windows Phone 的行为。如果运行此应用程序,输出将是

现在我必须为自己编写一个外观应用程序,它会在内部为我完成所有这些工作。 我将编写一个类,它只会向我公开两个方法,例如 StartJogging
和 StopJogging
。它将在内部负责完成所有这些活动。所以让我现在写一个外观:
class MyJoggingFacade
{
// These handles will be passed to this facade in a real application
// also on actual device these controllers will be singleton too.
GPSController gps = new GPSController();
MobileDataController data = new MobileDataController();
MusicController zune = new MusicController();
WifiController wifi = new WifiController();
SportsTrackerApp app = null;
public void StartJogging()
{
// 1. Turn off the wifi
wifi.IsSwitchedOn = false;
// 2. Switch on the Mobile Data
data.IsSwitchedOn = true;
// 3. Turn on the GPS
gps.IsSwitchedOn = true;
// 4. Turn on the Music
zune.IsSwitchedOn = true;
// 5. Start the Sports-Tracker
app = new SportsTrackerApp();
app.Start();
}
public void StopJogging()
{
// 0. Share Sports tracker stats on twitter and facebook
app.Share();
// 1. Stop the Sports Tracker
app.Stop();
// 2. Turn off the Music
zune.IsSwitchedOn = false;
// 3. Turn off the GPS
gps.IsSwitchedOn = false;
// 4. Turn off the Mobile Data
data.IsSwitchedOn = false;
// 5. Turn on the wifi
wifi.IsSwitchedOn = true;
}
}
现在,用户只需进行最少的手动操作即可实现相同的功能。
static void Main(string[] args)
{
MyJoggingFacade facade = new MyJoggingFacade();
facade.StartJogging();
Console.WriteLine();
facade.StopJogging();
}

在总结之前,让我们将此实现的类图与外观模式进行比较

注意:示例应用程序讨论了应用程序和控制器。这些的实际实现必须以单独的应用程序的形式存在。为了说明外观模式,我们已将它们全部视为单个应用程序的类。如果我们实际实现这样一个应用程序,它也将是一个外观,但它将是一个外观应用程序,而不是外观模式的实现。
关注点
在本文中,我们讨论了外观模式。通常,此模式与适配器模式混淆,但实际上,适配器模式实际上向客户端呈现了系统的修改后的接口,并且原始接口不可访问。另一方面,外观模式提供了子系统的一个更简单的接口。原始对象/系统仍然可以被访问。我希望这篇文章对您有所帮助。
历史
- 2012 年 10 月 22 日:第一个版本。