意圖:
- 爲一個複雜子系統提供一個簡單接口。
- 客戶程序與抽象類的實現部分之間存在很大的依賴性。
- 當你需要構件一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,可以讓它們僅通過facade進行通訊,從而簡化了它們之間的依賴關係。
- Facade(Compiler):
- 知道哪些子系統類負責處理請求;
- 將客戶的請求代理給適當的子系統對象。
- Subsystem classes(Scanner, Parser, ProgramNode):
- 實現子系統的功能;
- 處理由Facade對象指派的任務;
- 沒有Facade的任何相關信息。
- 客戶程序通過發送請求給Facade與子系統通訊,Facade將這些消息轉發給適當的子系統對象。
- 使用Facade的客戶程序不需要直接訪問子系統對象
- 對客戶屏蔽子系統組件,減少了客戶處理的對象的數目,並使得子系統使用起來更加方便
- 實現了子系統與客戶之間的耦合關係,而子系統內部的功能組件往往是緊耦合的。鬆耦合關係使得子系統的組件變化不會影響到它的客戶。具體如下:
- Facade模式有助於建立層次結構系統
- 有助於對對象之間的依賴關係分層
- 消除複雜的循環依賴關係
- 降低編譯依賴性,限制重要系統中較小的變化所需要的重編譯工作
- 有利於簡化系統在不同平臺之間的移植過程
- 如果應用需要,它並不限制它們使用子系統類。因此你可以在系統易用性和通用性之間加以選擇。
- 降低客戶-子系統之間的耦合度:兩種方式
- 用抽象類實現Facade而它的具體子類對應不同的子系統實現,這可以進一步降低客戶與子系統的耦合度
- 用不同的子系統對象配置Facade,僅需要對它的子系統對象進行替換即可
- 公共子系統類與私有子系統類:
- 用類的思想思考子系統:一個子系統與一個類的相似之處是,它們都有接口並且它們都封裝了一些東西——類封裝了狀態和操作,而子系統封裝了一些類。
- 子系統的公共接口包含所有的客戶程序可以訪問的類
- 子系統的私有接口僅用於對子系統進行擴充和維護
- Facade類是公共接口的一部分,但它不是唯一的部分,子系統的其他部分通常也是公共的
class Scanner
{
public:
Scanner(istream&);
virtual ~Scanner();
virtual Token& Scan();
private:
istream& _inputStream;
};
class Parser
{
public:
Parser();
virtual ~Parser();
virtual void Parse(Scanner&, ProgramNodeBuilder&);
};
class ProgramNodeBuilder
{
public:
ProgramNodeBuilder();
virtual ProgramNode* NewVariable (
const char* variableName
) const;
virtual ProgramNode* NewAssignment (
ProgramNode* variable, ProgramNode* expression
) const;
virtual ProgramNode* NewRetrurnStatement (
ProgramNode* value
) const;
virtual ProgramNode* NewCondition (
ProgramNode* condition,
ProgramNode* truePart,
ProgramNode* falsePart
) const;
ProgramNode* _node;
private:
ProgramNode* _node;
};
class ProgramNode {
public:
virtual void GetSourcePositon(int& line, int& index);
virtual void Add(ProgramNode*);
virtual void Remove(ProgramNode*);
virtual void Traverse(CodeGenerator&);
protected:
ProgramNode();
};
CodeGenerator:一個訪問者(訪問者模式),有兩個子類StackMachineCodeGenerator和RISCCodeGenerator,分別爲不同的硬件體系結構生成機器代碼。
class CodeGenerator {
public:
virtual void Visit(StatementNode*);
virtual void Visit(ExpressionNode*);
protected:
CodeGenerator(BytecodeStream&);
protected:
BytecodeStream& _output;
};
void ExpressionNode::Traverse (CodeGenerator& cg)
{
cg.Visit(this);
ListIterator<ProgramNode*> i(_children);
for (i.First(); !i.IsDone(); i.Next())
{
i.CurrentItem()->Traverse(cg);
}
}
class Compiler
{
public:
Compiler();
virtual void Compile(istream&, BytecodeStream);
};
void Compiler::Compile(istream& input, BytecodeStream& output)
{
Scanner scanner(input);
ProgramNodeBuilder builder;
Parser parser;
parser.Parse(scanner, builder);
RISCCodeGenerator generator(builder);
ProgramNode* parseTree = builder.GetRootNode();
parserTree->Traverse(generator);
}