结构模式->外观模式
外观模式 跟建造者模式类似 为了减少子类跟客户端的耦合性 建造一个中间类来处理之间相互关系,但侧重点不一样
外观模式概述 Facade Pattern
不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶、茶具和开水,如图1(A)所示,而去茶馆喝茶,最简单的方式就是跟茶馆服务员说想要一杯什么样的茶,是铁观音、碧螺春还是西湖龙井?正因为茶馆有服务员,顾客无须直接和茶叶、茶具、开水等交互,整个泡茶过程由服务员来完成,顾客只需与服务员交互即可,整个过程非常简单省事,如图1(B)所示。
图1 两种喝茶方式示意图
在软件开发中,有时候为了完成一项较为复杂的功能,一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现,由于涉及到的类比较多,导致使用时代码较为复杂,此时,特别需要一个类似服务员一样的角色,由它来负责和多个业务类进行交互,而客户类只需与该类交互。外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类充当了软件系统中的“服务员”,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。在外观模式中,那些需要交互的业务类被称为子系统(Subsystem)。如果没有外观类,那么每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大,如图2(A)所示;而引入外观类之后,客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度,如图2(B)所示。
图2 外观模式示意图
外观模式中,一个子系统的外部与其内部的通信通过一个统一的外观类进行,外观类将客户类与子系统的内部复杂性分隔开,使得客户类只需要与外观角色打交道,而不需要与子系统内部的很多对象打交道。
外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 |
外观模式应该是用的很多的一种模式,特别是当一个系统很复杂时,系统提供给客户的是一个简单的对外接口,而把里面复杂的结构都封装了起来。客户只需使用这些简单接口就能使用这个系统,而不需要关注内部复杂的结构。DP一书的定义:为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。举个编译器的例子,假设编译一个程序需要经过四个步骤:词法分析、语法分析、中间代码生成、机器码生成。学过编译都知道,每一步都很复杂。对于编译器这个系统,就可以使用外观模式。可以定义一个高层接口,比如名为Compiler的类,里面有一个名为Run的函数。客户只需调用这个函数就可以编译程序,至于Run函数内部的具体操作,客户无需知道。下面给出UML图,以编译器为实例。
class Scanner
{
public:
void Scan() { cout<<"词法分析"<<endl; }
};
class Parser
{
public:
void Parse() { cout<<"语法分析"<<endl; }
};
class GenMidCode
{
public:
void GenCode() { cout<<"产生中间代码"<<endl; }
};
class GenMachineCode
{
public:
void GenCode() { cout<<"产生机器码"<<endl;}
};
//高层接口
class Compiler
{
public:
void Run()
{
Scanner scanner;
Parser parser;
GenMidCode genMidCode;
GenMachineCode genMacCode;
scanner.Scan();
parser.Parse();
genMidCode.GenCode();
genMacCode.GenCode();
}
};
int main()
{
Compiler compiler;
compiler.Run();
return 0;
}
这就是外观模式,它有几个特点(摘自DP一书), 外观模式在构建大型系统时非常有用。
(1)它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
(2)它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
(3)如果应用需要,它并不限制它们使用子系统类。
结合上面编译器这个例子,进一步说明。对于
(1),编译器类对客户屏蔽了子系统组件,客户只需处理编译器的对象就可以方便的使用子系统。
(2),子系统的变化,不会影响到客户的使用,体现了子系统与客户的松耦合关系。
(3),如果客户希望使用词法分析器,只需定义词法分析的类对象即可,并不受到限制。
外观模式完美体现了依赖倒转原则跟迪米特法则 (类与类减少相互依赖)
在设计软件初期就要有意识的将不同两个层分离,客户类----facade-------子系统类 ,
对于一个复杂老系统 我们可以分2组。一组负责了解facade接口 一组负责开发facade与老系统的交互。
股票类似直接处理子类 基金类似通过facade中转处理子类