2

示例代码为了尽可能突显设计模式的特征,采用了极简代码。尽量避免其他代码对理解设计模式产生干扰

定义

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
简而言之就是,外观模式可以使客户端不用关心各个子系统之间的交互逻辑,它只需要知道担任“外观角色”的接口是哪个就足够了。

结构导图(刘伟老师的博客

外观模式结构导图


代码

场景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() 即可成功订餐!

以上。


什么么么么
382 声望4 粉丝