示例代码为了尽可能突显设计模式的特征,采用了极简代码。尽量避免其他代码对理解设计模式产生干扰
定义
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
简而言之就是,外观模式可以使客户端不用关心各个子系统之间的交互逻辑,它只需要知道担任“外观角色”的接口是哪个就足够了。
结构导图(刘伟老师的博客)
代码
场景1
某个周六临近中午时,小明饿了!为了填饱肚子,他只能从床上爬起来,准备做饭。
要知道,这可不是件容易的事情!毕竟自己做饭的话,需要先去菜市场买菜,洗菜,然后才能做菜。起码也得折腾一小时,才能吃上饭!
虽然很不情愿,但别无选择!
class BuyVegetables
{
/// <summary>
/// 买菜
/// </summary>
public static void Buy()
{
Console.WriteLine("买完食材了。");
}
}
class Cleanout
{
/// <summary>
/// 洗菜
/// </summary>
public static void Clean()
{
Console.WriteLine("该洗的菜都洗好了。");
}
}
class Cooking
{
/// <summary>
/// 做菜
/// </summary>
public static void Cook()
{
Console.WriteLine("饭菜做好了。");
}
}
该忙的都忙完了,可以开饭了!
class Program
{
static void Main(string[] args)
{
Console.WriteLine("该吃饭了···");
BuyVegetables.Buy();
Cleanout.Clean();
Cooking.Cook();
Console.WriteLine("吃饱喝足。");
}
}
这顿饭还真是把小明折腾惨了!!!
场景2
一周过去了···
又到了周六,又到了临近中午的时间点,小明又饿了···
多么似曾相识的一幕~~~
但今天他实在不想再做饭了,所以,他选择了订外卖!!!
不过,想订外卖,首先得有餐馆的联系方式。
这个订餐服务
其实就充当了外观者的逻辑入口。
class Restaurant
{
/// <summary>
/// 外卖服务
/// </summary>
public static void Order()
{
Console.WriteLine("已收到订单,正在出餐···");
BuyVegetables.Buy();
Cleanout.Clean();
Cooking.Cook();
Console.WriteLine("已出餐,正在配送中···");
}
}
有了餐馆的联系方式后,就简单了。
class Program
{
static void Main(string[] args)
{
Console.WriteLine("该吃饭了,点个外卖吧···");
Restaurant.Order();
Console.WriteLine("收到外卖,开饭!");
Console.WriteLine("吃饱喝足,顺便还打了个饱嗝···");
}
}
这次可轻松了。
总结
场景1中,客户(小明)与吃饭这件事的交互相当麻烦,整个流程他自己做下来要费不少心思!实际工作中,这种场景非常常见,每一次都把子系统的逻辑耦合到客户端内,那么客户端将变得相当臃肿,且不稳定。
此时,提供一个中间件(外观者),也就是场景2中的“餐馆”,这样的话,小明只要一个电话,买菜,洗菜,做菜这种事情就都有人帮他解决了。实际工作中,也可以提供一个外观者,由它来负责和各个子系统(或者子功能)的交互。这个外观者对客户端提供一个入口方法,而客户端只需要调用这个入口方法,就可以把所有想做的事情全部处理掉,这样势必会减轻客户端的复杂度。
补充讨论
如果某一天,小明只是随便点了一份清汤面,这样的话餐馆就不用洗菜,只需要买面条,并且煮好送到小明的手里就好了。那怎么办呢?难道要改外观者的代码,把里面的Cleanout.Clean();
代码删掉?这岂不是违反了开闭原则?
是的,如果这样处理,那么势必会违反开闭原则!
怎么办呢?此时可以把外观者角色抽象出来!
interface IRestaurant
{
/// <summary>
/// 订餐服务
/// </summary>
void Order();
}
然后实现一个具体外观者-面馆。
class NoodleRestaurant : IRestaurant
{
public void Order()
{
Console.WriteLine("已收到订单,正在出餐···");
BuyVegetables.Buy();
Cooking.Cook();
Console.WriteLine("已出餐,正在配送中···");
}
}
这样小明只需要在想吃面的时候,使用new NoodleRestaurant().Order()
即可成功订餐!
以上。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。