十三.结构型设计模式——Facade Pattern(外观模式)
-
定义
外观模式提供了一个统一的接口去访问多个子系统的多个不同的接口,外观模式定义了一个高层次的接口,使得子系统更容易被使用。
UML类图如下:
其中类和对象的关系为:
1. Facade(外形类):知道哪些子系统负责处理哪些请求;将客户的请求传递给相应的子系统对象处理。
2. Subsystem(子系统类):实现子系统的功能;处理由Facade传过来的任务;子系统不用知道Facade,在任何地方也没有引用Facade。
典型应用的顺序图如下:
-
实例1——抵押申请审核
抵押申请要得到三个审核,要检查银行是不是有足够存款,抵押物价格评估是不是合理,客户信誉评估是不是好。这三个评估交给三个子系统独立完成,抵押申请审核要调用这三个子系统的方法,统一结果后决定审核是不是合格。其类关系如图:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//子系统 类A
class Bank
{
public bool SufficientSavings(Customer c)
{
Console.WriteLine("Check bank for {0}", c.Name);
return true;
}
}
//子系统 类B
class Credit
{
public bool GoodCredit(int amount, Customer c)
{
Console.WriteLine("Check Credit for {0}", c.Name);
return true;
}
}
//子系统 类C
class Loan
{
public bool GoodLoan(Customer c)
{
Console.WriteLine("Check loan for {0}", c.Name);
return true;
}
}
//申请抵押的客户
class Customer
{
private string name;
public Customer(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
//Facade
class MortgageApplication
{
int amount;
private Bank bank = new Bank();
private Loan loan = new Loan();
private Credit credit = new Credit();
//Constructors
public MortgageApplication(int amount)
{
this.amount = amount;
}
public bool IsEligible(Customer c)
{
if (!bank.SufficientSavings(c))
return false;
if (!loan.GoodLoan(c))
return false;
if (!credit.GoodCredit(amount, c))
return false;
return true;
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
MortgageApplication mortgage = new MortgageApplication(12500);
mortgage.IsEligible(new Customer("Gabrielle McKinsey"));
Console.Read();
}
}
class Bank
{
public bool SufficientSavings(Customer c)
{
Console.WriteLine("Check bank for {0}", c.Name);
return true;
}
}
//子系统 类B
class Credit
{
public bool GoodCredit(int amount, Customer c)
{
Console.WriteLine("Check Credit for {0}", c.Name);
return true;
}
}
//子系统 类C
class Loan
{
public bool GoodLoan(Customer c)
{
Console.WriteLine("Check loan for {0}", c.Name);
return true;
}
}
//申请抵押的客户
class Customer
{
private string name;
public Customer(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
//Facade
class MortgageApplication
{
int amount;
private Bank bank = new Bank();
private Loan loan = new Loan();
private Credit credit = new Credit();
//Constructors
public MortgageApplication(int amount)
{
this.amount = amount;
}
public bool IsEligible(Customer c)
{
if (!bank.SufficientSavings(c))
return false;
if (!loan.GoodLoan(c))
return false;
if (!credit.GoodCredit(amount, c))
return false;
return true;
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
MortgageApplication mortgage = new MortgageApplication(12500);
mortgage.IsEligible(new Customer("Gabrielle McKinsey"));
Console.Read();
}
}
-
实例2——冲茶
假定我们要设计一个冲茶系统,包括茶杯、水、茶包各类,我们创造一个Facade类来耦合各个类以完成操作。其类图如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//定义子系统类TeaBag(茶包)
public class TeaBag
{
public TeaBag()
{
Console.WriteLine("清香的茶包准备好了");
}
}
//定义子系统类Water
public class Water
{
bool waterIsBoiling;
public Water()
{
SetWaterBoiling(false);
Console.WriteLine("纯净的水准备好了");
}
public void BoilFacadeWater()
{
SetWaterBoiling(true);
Console.WriteLine("水在沸腾");
}
public void SetWaterBoiling(bool isWaterBoiling)
{
waterIsBoiling = isWaterBoiling;
}
public bool GetWaterIsBoiling()
{
return waterIsBoiling;
}
}
//定义子系统类TeaCup(茶杯)
public class TeaCup
{
bool teaBagIsSteeped;
Water facadeWater;
TeaBag facadeTeaBag;
public TeaCup()
{
SetTeaBagIsSteeped(false);
Console.WriteLine("茶杯准备好了");
}
public void SetTeaBagIsSteeped(bool isTeaBagSteeped)
{
teaBagIsSteeped = isTeaBagSteeped;
}
public bool GetTeaBagIsSteeped()
{
return teaBagIsSteeped;
}
public void AddFacadeTeaBag(TeaBag facadeTeaBagIn)
{
facadeTeaBag = facadeTeaBagIn;
Console.WriteLine("茶包放在茶杯了");
}
public void AddFacadeWater(Water facadeWaterIn)
{
facadeWater = facadeWaterIn;
Console.WriteLine("水倒入杯子了");
}
public void SteepTeaBag()
{
if (facadeTeaBag != null && facadeWater != null && facadeWater.GetWaterIsBoiling())
{
Console.WriteLine("杯子中已经倒有茶");
SetTeaBagIsSteeped(true);
}
else
{
Console.WriteLine("杯子里还没有茶");
SetTeaBagIsSteeped(false);
}
}
public override string ToString()
{
if (this.GetTeaBagIsSteeped())
return "一杯又香又浓的茶冲好了";
else
{
string tempString = "一个杯子";
if (facadeWater != null)
{
if (facadeWater.GetWaterIsBoiling())
tempString += "放有沸腾的水";
else
tempString += "放有冷水";
}
else
tempString += "没有放水";
if (facadeTeaBag != null)
tempString += "有一个茶包";
else
tempString += "没有茶包";
return tempString;
}
}
}
//FacadeCuppaMaker耦合各系统来冲茶
public class FacadeCuppaMaker
{
public FacadeCuppaMaker()
{
Console.WriteLine("FacadeCuppaMaker准备好为你冲茶了!");
}
public TeaCup MakeACuppa()
{
TeaCup cup = new TeaCup();
TeaBag teaBag = new TeaBag();
Water water = new Water();
cup.AddFacadeTeaBag(teaBag);
water.BoilFacadeWater();
cup.AddFacadeWater(water);
cup.SteepTeaBag();
return cup;
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
FacadeCuppaMaker cuppaMaker = new FacadeCuppaMaker();
TeaCup teaCup = cuppaMaker.MakeACuppa();
Console.WriteLine(teaCup.ToString());
Console.Read();
}
}
public class TeaBag
{
public TeaBag()
{
Console.WriteLine("清香的茶包准备好了");
}
}
//定义子系统类Water
public class Water
{
bool waterIsBoiling;
public Water()
{
SetWaterBoiling(false);
Console.WriteLine("纯净的水准备好了");
}
public void BoilFacadeWater()
{
SetWaterBoiling(true);
Console.WriteLine("水在沸腾");
}
public void SetWaterBoiling(bool isWaterBoiling)
{
waterIsBoiling = isWaterBoiling;
}
public bool GetWaterIsBoiling()
{
return waterIsBoiling;
}
}
//定义子系统类TeaCup(茶杯)
public class TeaCup
{
bool teaBagIsSteeped;
Water facadeWater;
TeaBag facadeTeaBag;
public TeaCup()
{
SetTeaBagIsSteeped(false);
Console.WriteLine("茶杯准备好了");
}
public void SetTeaBagIsSteeped(bool isTeaBagSteeped)
{
teaBagIsSteeped = isTeaBagSteeped;
}
public bool GetTeaBagIsSteeped()
{
return teaBagIsSteeped;
}
public void AddFacadeTeaBag(TeaBag facadeTeaBagIn)
{
facadeTeaBag = facadeTeaBagIn;
Console.WriteLine("茶包放在茶杯了");
}
public void AddFacadeWater(Water facadeWaterIn)
{
facadeWater = facadeWaterIn;
Console.WriteLine("水倒入杯子了");
}
public void SteepTeaBag()
{
if (facadeTeaBag != null && facadeWater != null && facadeWater.GetWaterIsBoiling())
{
Console.WriteLine("杯子中已经倒有茶");
SetTeaBagIsSteeped(true);
}
else
{
Console.WriteLine("杯子里还没有茶");
SetTeaBagIsSteeped(false);
}
}
public override string ToString()
{
if (this.GetTeaBagIsSteeped())
return "一杯又香又浓的茶冲好了";
else
{
string tempString = "一个杯子";
if (facadeWater != null)
{
if (facadeWater.GetWaterIsBoiling())
tempString += "放有沸腾的水";
else
tempString += "放有冷水";
}
else
tempString += "没有放水";
if (facadeTeaBag != null)
tempString += "有一个茶包";
else
tempString += "没有茶包";
return tempString;
}
}
}
//FacadeCuppaMaker耦合各系统来冲茶
public class FacadeCuppaMaker
{
public FacadeCuppaMaker()
{
Console.WriteLine("FacadeCuppaMaker准备好为你冲茶了!");
}
public TeaCup MakeACuppa()
{
TeaCup cup = new TeaCup();
TeaBag teaBag = new TeaBag();
Water water = new Water();
cup.AddFacadeTeaBag(teaBag);
water.BoilFacadeWater();
cup.AddFacadeWater(water);
cup.SteepTeaBag();
return cup;
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
FacadeCuppaMaker cuppaMaker = new FacadeCuppaMaker();
TeaCup teaCup = cuppaMaker.MakeACuppa();
Console.WriteLine(teaCup.ToString());
Console.Read();
}
}
-
优势和缺陷
外观模式提供了一个简单且公用的接口去处理复杂的子系统,并且没有减少子系统的功能。它遮蔽了子系统的复杂性,避免了客户与子系统直接链接,它也减少了子系统与子系统间的连接,每个子系统都有它的Facade模式,每个子系统采用Facade模式去访问其他子系统。外观模式的劣势就是限制了客户的自由,减少了可变性。
-
应用情景
下面的情景很适合应用外观模式:
1. 你需要复杂的子系统提供一个简单的接口。
2. 客户与抽象的实现类中存在若干依赖。
3. 子系统分层是必要的或架构要求的情况下。