引言
公司联合办公产品上线已有一段时间,已有不少项目组基于联合办公产品二次开发。在二次开发过程中,难免遇到各种问题,如不清楚联合办公产品的配置、部署,联合办公产品本身的Bug等,这时候项目组就会来咨询产品相关问题。咨询过程如下图:
这种结构有很多问题,首先是各个项目组得了解产品组各个产品是谁负责,可能一个项目组需要与产品组的若干个成员联系,解决相关问题。而一个产品组组员可能需要面对多个项目组的咨询,哪怕这种咨询很可能是一样的。为了减轻产品组开发人员的工作量,我们在产品组里面成立了一个支持组,所有的咨询和产品支持工作,转入支持组,结构如下:
这是我们在解决项目组与产品组有比较复杂的咨询关系时候采取的解决方法。而此方法,其实就是我们说的外观模式。
概述
从引言的描述中,我们可以看到项目组组员与产品组组员之间有比较强的依赖关系,如果产品组内部由于组员变化调整将影响到对外的咨询,产品咨询工作。如何解决需求方(客户端)对多个复杂服务商(复杂子系统)的强依赖关系?如何简化需求方和复杂服务商之间的沟通通道(调用接口)?
意图
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。[GOF 《设计模式》]
Facade解析
Facade模式其实是对复杂子系统的封装。将复杂子系统可能产生的变化,封装在Facade类里面,对外提供一组统一的简洁的接口,而将复杂的子系统直接的调用关系,封装在Facade类内部。避免了,客户端程序对子系统对象的直接调用。
事实上,Facade处理的是一组接口,这组接口之间应该有比较强的依赖关系或者相互关系。比如网上举的一个Facade模式的一个例子:一个抵押系统,一个客户想去抵押房子,银行系统需要做3件事:一、存款系统中查询是否有足够存款。二、信用系统中查询是否有足够的信用。三、在抵押系统中查询是否已经抵押。这三者之间都是客户做抵押时需要的交互的对象,可能彼此直接还有约束关系,比如存款达到1千万就可以只用信用达到4级即可等等,这些关系就可以在Facade中进行处理。而如果没有Facade类,则客户端需要调用三个子系统接口,然后还得分析约束关系来判断自己是否能抵押。有了Facade之后,把散落在各个客户端的逻辑封装,既简化了接口,又内聚了可能的变化。
示例代码
/// <summary>
/// 项目组
/// </summary>
class ProjectTeam
{
public void Ask(Question q)
{
ProductTeam PT = new ProductTeam();
PT.Answer(q);
}
}
/// <summary>
/// 问题
/// </summary>
internal class Question
{
public string Message = string.Empty;
public QuestionType Type { get; set; }
}
/// <summary>
/// 问题类型
/// </summary>
public enum QuestionType
{
WebIM = 0,
Portal = 1,
WorkFlow = 2
}
/// <summary>
/// 场景
/// </summary>
internal class Run
{
private void Main()
{
ProjectTeam TeamA = new ProjectTeam();
ProjectTeam TeamB = new ProjectTeam();
ProjectTeam TeamC = new ProjectTeam();
Question Q1 = new Question { Message="A", Type= QuestionType.Portal };
Question Q2 = new Question { Message = "B", Type = QuestionType.WebIM };
Question Q3 = new Question { Message = "C", Type = QuestionType.WorkFlow };
TeamA.Ask(Q1);
TeamA.Ask(Q2);
TeamB.Ask(Q1);
TeamB.Ask(Q3);
TeamC.Ask(Q2);
TeamC.Ask(Q3);
}
}
/// <summary>
/// 产品组
/// </summary>
internal class ProductTeam
{
public bool Answer(Question q)
{
switch (q.Type)
{
case QuestionType.WorkFlow:
this.WorkFlowAnswer(q);
break;
case QuestionType.WebIM:
this.WebIMAnswer(q);
break;
case QuestionType.Portal:
this.PortalAnswer(q);
break;
}
return true;
}
bool WebIMAnswer(Question q)
{
return q.Type == QuestionType.WebIM;
}
bool PortalAnswer(Question q)
{
return q.Type == QuestionType.Portal;
}
bool WorkFlowAnswer(Question q)
{
return q.Type == QuestionType.WorkFlow;
}
}
总结
外观模式应该是结构型设计模式里面比较简单的一种,理解也相对容易。实际使用中,我们在不自觉中已经有使用,此处只是做个简单的总结。