设计模式——外观模式
需求
.NET程序员大多使用过System.SqlClient、System.OracleClient、System.OleDb,尽管针对的数据库不同,这些类库体系都是实现访问数据库功能。尽管体系结构很相似,使用方法很相似,但是各对应类名称的不同,还是需要各写各的,如果能进行封装,形成一套统一的方法调用就好了。
从理论层次来说就是,在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着子系统的变化而变化。那么如何简化客户程序与子系统之间的交互接口?如何将复杂系统的内部子系统与客户程序之间的依赖解耦?这就是要说的外观模式(Façade Pattern)。
定义
意图:外部与子系统的通信必须通过统一的门面对象进行。外观模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。即当子系统复杂或者繁锁时,我们让子系统提供一个窗口,程序中称为接口,其它程序或者对象就通过这个窗口(接口)与此子系统联系。这样就简化了子系统的使用。
外观模式由2部分组成:(1)外观类(Facade),定义外观规格;(2)其它需要封装的子系统(SubSystem)。
外观模式又叫门面模式。门面是一个类,它把客户对象所需要的子系统的功能简化到简单的接口上,客户对象不直接与子系统内部的对象打交道,而是简单地调用门面对象所提供的接口,门面对象再去调用子系统内部的具体功能。
由于各子系统的使用简化成一个统一的外观类,所以外观类常常用单例或者静态来实现。
案例
class Program
{
static voidMain(string[] args)
{
// 客户程序
Customer cust = new Customer("张三");
MortgageFacade mortgage = new MortgageFacade();
bool isEligible = mortgage.IsEligible(cust, 10000);
string result = isEligible ? "审查完成:{0}具有贷款资格!" : "审查完成:{0}不具有贷款资格!";
Console.WriteLine(result, cust.Name);
}
}
// 一个需要贷款的客户
public class Customer
{
public Customer(string name) { this._Name = name; }
private string _Name;
public string Name { get { return _Name; } }
}
// 三个需要封装的子系统
// 银行子系统
public class Bank
{
public bool HasSufficientSavings(Customer c, int amount)
{
Console.WriteLine("\t检查{0}银行存款... ", c.Name);
return true;
}
}
// 信用子系统
public class Credit
{
public bool HasGoodCredit(Customer c)
{
Console.WriteLine("\t检查{0}的信用记录...", c.Name);
return true;
}
}
// 贷款子系统
public class Loan
{
public bool HasNoBadLoans(Customer c)
{
Console.WriteLine("\t检查{0}贷款记录...", c.Name);
return true;
}
}
// 外观类
public class MortgageFacade
{
private Bank bank = new Bank();
private Loan loan = new Loan();
private Credit credit = new Credit();
// 是否合格的贷款客户
public bool IsEligible(Customer cust, int amount)
{
Console.WriteLine("开始审查{0}的贷款资格:", cust.Name);
if (!bank.HasSufficientSavings(cust, amount)) return false;
if (!loan.HasNoBadLoans(cust)) return false;
if (!credit.HasGoodCredit(cust)) return false;
return true;
}
}
优缺点
优点:外观模式通过提供一个统一的对外接口,避免了外部系统和子系统之间的直接联系,从而降低了系统间的依赖,也降低了常常需要使用多个子系统而导致的复杂度。
缺点:限制了外部系统对子系统调用的灵活性,只能按照外观类中提供的方式来调用子系统,所以需要精心设计外观系统。
适用场景
当一个或多个复杂的系统需要对外提供接口时,就需要对外提供的接口统一封装在一个外观类里,供外系统使用。
外观模式注重的是简化接口,它更多的时候是从架构的层次去看整个系统,而并非单个类的层次。如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性与通用性之间选择。
补充