引言
在软件测试中,一般都是在功能测试稳定的情况下再进行UI自动化测试、或者进行性能测试。如果一个一个进行太麻烦,此时可以使用对外提供一个简单接口,通过这个接口可以访问内部一群接口。例如进行UI自动化测试, 那么执行功能测试后再执行自动化测试。在软件开发过程中,将对外提供了一个统一的接口,用来访问子系统中的一群接口的模式称为外观模式。这种模式可以应对客户端程序与复杂系统的内部子系统进行耦合而导致客户端程序随着子系统的变化而变化,将复杂系统的内部子系统与客户端之间的依赖解耦。
概念
外观模式(Facade Pattern)是一种结构型设计模式, 能为复杂系统、 程序库或框架提供一个简单 (但有限) 的接口。
外观定义了一个高层接口,让子系统更容易使用。使用外观模式时,我们创建了一个统一的类,用来包装子系统中一个或多个复杂的类,客户端可以直接通过外观类来调用内部子系统中方法,从而外观模式让客户和子系统之间避免了紧耦合。
结构图
角色
外观角色(Facade):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。
子系统角色(SubSystem Classes):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
实现
例如我们实现引言中提到的手动测试、自动化测试、性能测试。
using System;
namespace Facade
{
class Program
{
/// <summary>
/// 如果不使用外观模式,则需要调用三次测试执行
/// 此时客户端只需要调用外观类中的方法就可以了,简化了客户端的操作
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
StartTest test = new StartTest();
test.start();
Console.Read();
}
}
/// <summary>
/// 外观类,开始测试
/// </summary>
public class StartTest
{
private ManuaTest manua;
private AutoTest auto;
private StressTest stress;
public StartTest()
{
manua = new ManuaTest();
auto = new AutoTest();
stress = new StressTest();
}
public void start()
{
manua.test();
auto.test();
stress.test();
}
}
/// <summary>
/// 子系统类A,手工测试
/// </summary>
public class ManuaTest
{
public void test()
{
Console.WriteLine("执行手工测试");
}
}
/// <summary>
/// 子系统类B,自动化测试
/// </summary>
public class AutoTest
{
public void test()
{
Console.WriteLine("执行自动化测试");
}
}
/// <summary>
/// 子系统类C,压力测试
/// </summary>
public class StressTest
{
public void test()
{
Console.WriteLine("执行压力测试");
}
}
}
运行结果
执行手工测试
执行自动化测试
执行压力测试
优缺点
优点
- 外观模式降低了客户端对子系统使用的复杂性。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
- 外观模式松散了客户端与子系统的耦合关系,让子系统内部的模块能更容易扩展和维护。
- 通过合理使用外观模式,可以帮助我们更好的划分访问的层次。
缺点
- 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活 性。
- 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。
适用场景
- 当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式。
- 客户端程序与多个子系统之间存在很大的依赖性。引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。