目录
一、定义
为子系统定义一组统一的接口,这个高级接口会让子系统更容易被使用。
相当于我们去餐厅吃饭,我们不需要知道碗筷放在那里,不需要关心这道菜是怎么做的,我们只需要询问服务员就可以在这里就餐。
二、适用场景
在游戏中我们会有很多个系统,成就、UI、体力、战斗系统等等多种系统,我们都可以为这些子系统提供一个接口方便访问。
三、快速理解
例:RiLee最近是真的惨,人老头还秃了,只能跑到餐厅来干服务员。这天来了一个3人家庭(爸爸、妈妈、孩子),他们也是来到这这个新开的餐厅吃饭,好巧不巧的是,RiLee负者的就是他们那一桌,于是就发生下面一个情况,第一次来这个餐厅不知道点菜,就餐,碗筷放置,以及是否是自己拿餐等等流程。身为服务员的RiLee知道并且可以提供给他们,他们此时就会对RiLee所在的餐厅印象好坏,此时RiLee就是这家餐厅的外观;
我们可以看见自助餐都是自己拿菜,自己拿碗筷,自己煮等等类似于图中这种情况:会出现多种情况,可能没菜,可能没碗筷,可能在自己烹饪的时候受到伤害,这些都是顾客对餐厅不好印象。
一般的餐厅都是会有一个像RiLee一样的服务员为顾客服务(没菜,没碗筷,烹饪的时候受到伤害,这些可以避免给顾客不好的印象),拿菜、拿碗筷,烹饪等等都相当与一个餐厅的一部分(子系统),全部由服务员处理餐厅的大部分事项。:
现在就变成,有什么需求就向打工仔RiLee说就足够辽,还可以帮餐厅老板走向上市餐厅!!上述这种形式就是一种外观模式。
1、子系统
(1)拿菜(TakeVegetables)
public class TakeVegetables
{
public void DoAction()
{
Console.WriteLine("拿菜!!!");
}
}
(2)拿碗筷(TakeDishes)
public class TakeDishes
{
public void DoAction()
{
Console.WriteLine("拿碗筷!!!");
}
}
(3)烹饪(Cooking)
public class Cooking
{
public void DoAction()
{
Console.WriteLine("帮忙烹饪!!!");
}
}
2、外观类——RiLee
public class RiLee
{
TakeDishes takeDishes;
TakeVegetables takeVegetables;
Cooking cooking;
public RiLee()
{
takeDishes = new TakeDishes();
takeVegetables = new TakeVegetables();
cooking = new Cooking();
}
public void ClientToDishes()
{
takeDishes.DoAction();
}
public void ClientToVegetables()
{
takeVegetables.DoAction();
}
public void ClientToCooking()
{
cooking.DoAction();
}
}
3、客户端
传入的参数相当于你叫哪个服务员,可能很多个服务员,在这里只有我们的打工仔RiLee,调用的方法自然而然就是叫RiLee干啥啦。
因为这一家子都是顾客我们可以给他写一个基类(Client),方便后面扩展,毕竟可能他们的朋友路过然后和他们一起吃饭呢,我们就可以方便的扩展。
(1)顾客基类
public class Client
{
public virtual void Call(RiLee riLee) { }
}
(2)爸爸(ClientDad)
public class ClientDad : Client
{
public override void Call(RiLee riLee)
{
Console.WriteLine("ClientDad 叫服务员!!!");
riLee.ClientToDishes();
riLee.ClientToCooking();
riLee.ClientToVegetables();
}
}
(3)妈妈(ClientMom)
public class ClientMom : Client
{
public override void Call(RiLee riLee)
{
Console.WriteLine("ClientMom 叫服务员!!!");
riLee.ClientToDishes();
riLee.ClientToCooking();
riLee.ClientToVegetables();
}
}
(4)孩子
public class ClientChildren:Client
{
public override void Call(RiLee riLee)
{
Console.WriteLine("ClientChildren 叫服务员!!!");
riLee.ClientToDishes();
riLee.ClientToCooking();
riLee.ClientToVegetables();
}
}
(4)测试
public static void Main(string[] args)
{
/* 服务员*/
RiLee riLee = new RiLee();
/* 顾客*/
Client clientDad = new ClientDad();
clientDad.Call(riLee);
Client clientMom = new ClientMom();
clientMom.Call(riLee);
Client clientChildren = new ClientChildren();
clientChildren.Call(riLee);
}
控制台输出:
ClientDad 叫服务员!!!
拿碗筷!!!
帮忙烹饪!!!
拿菜!!!
ClientMom 叫服务员!!!
拿碗筷!!!
帮忙烹饪!!!
拿菜!!!
ClientChildren 叫服务员!!!
拿碗筷!!!
帮忙烹饪!!!
拿菜!!!
四、优缺点
(1)优点
简化接口:提供了一个简化的接口,使客户端更容易使用系统的功能。
降低耦合度:将客户端与子系统的具体实现解耦,允许系统的更改不会影响到客户端。
提高可维护性:隐藏了系统的复杂性,因此提高了系统的可维护性,减少了维护成本。
提供了更高层次的接口:允许为系统提供高层次的接口,有助于组织和管理复杂的代码。
(2)缺点
不符合开闭原则:如果系统的功能需要变化或扩展,可能需要修改外观类,这可能会违反开闭原则。
可能扩展子系统故障:外观模式将多个子系统封装在一个外观类中,如果外观类发生故障,整个系统可能会受到影响。