【设计模式】之外观模式(Facade)

来源:互联网 发布:mac wav 转 mp3 编辑:程序博客网 时间:2024/06/10 08:46

为子系统中的一组接口提供统一的接口,外观模式提供了一个更高层的接口,使得子系统比较容易使用。

Provide a unified interface toa set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystemeasier to use.

Facade应该是比较简单模式,只有两个参与者 Facade和subsystem classes。

Facade的主要功能是降耦,将subsystems封装成统一的接口,如此客户端只需要与Facade交互即可,无需关心子系统之间的依赖关系。

通过以下例子,了解一下编译器的设计是如何使用Facade模式的。


首先编译器子系统定义了一个ByteCodeStream类,实现了ByteCode对象流。一个ByteCode对象封装了一个字节码,字节码指定了机器指令。为了表示编程语言中的操作符,子系统也定义了一个Token类。

Scanner类使用字符流并生产标志符流,一次产生一个标志符。

class Scanner {public:    Scanner(istream&);    virtual ~Scanner();    virtual Token& Scan();private:    istream& _inputStream;};

Parser使用ProgramNodeBuilder类,利用从Scanner得到的标志符来构建一个语法分析树(Parse Tree)。

class Parser {public:    Parser();    virtual ~Parser();    virtual void Parse(Scanner&, ProgramNodeBuilder&);};

Parser通过回调ProgramNodeBuilder来增量地创建语法分析树,这些类利用了Builder模式来交互。

class ProgramNodeBuilder {public:    ProgramNodeBuilder();    virtual ProgramNode* NewVariable(        const char* variableName    ) const;    virtual ProgramNode* NewAssignment(        ProgramNode* variable, ProgramNode* expression    ) const;    virtual ProgramNode* NewReturnStatement(        ProgramNode* value    ) const;    virtual ProgramNode* NewCondition(        ProgramNode* condition,        ProgramNode* truePart, ProgramNode* falsePart    ) const;    // ...    ProgramNode* GetRootNode();private:    ProgramNode* _node;};

语法分析树是由ProgramNode子类的实例构成的,比如StatementNode, ExpressionNode等等。ProgramNode的结构就是Composite模式的实例。ProgramNode定义了一个接口用来控制程序节点以及它的子节点。

class ProgramNode {public:    // program node manipulation    virtual void GetSourcePosition(int& line, int& index);    // ...    // child manipulation    virtual void Add(ProgramNode*);    virtual void Remove(ProgramNode*);    // ...    virtual void Traverse(CodeGenerator&);protected:    ProgramNode();}
Traverse操作付接收一个CodeGenerator对象。ProgramNode子类利用这个对象来生成BytecodeStream中的ByteCode形式的机器码。CodeGenerator类是一个Visitor模式。

class CodeGenerator {public:    virtual void Visit(StatementNode*);    virtual void Visit(ExpressionNode*);    // ...protected:    CodeGenerator(BytecodeStream&);protected:    BytecodeStream& _output;};

CodeGenerator可以有StackMachieCodeGenerator、RISCCodeGenerator等子类,他们为不同的硬件架构生成机器码。

每一个ProgramNode的子类实现了Traverse来调用它子节点ProgramNode对象的Traverse方法,这个是一个递归的过程。比如,ExpressionNode定义如下的Traverse

void ExpressionNode::Traverse(CodeGenerator& cg) {    cg.Visit(this);    ListIterator<ProgramNode*> i(_children);    for (i.First(); !i.IsDone(); i.Next()) {        i.currentItem()->Traverse(cg);    }}

我们上面讨论的类构成了Compiler的子系统。现在我们引入Compiler类,一个可以把所有这些东西组织在一起的Facade。Compiler为特定的机器提供了一个简单的接口,这个接口可以编译源码并生成码(code)。

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(output);    ProgramNode* parseTree = builder.GetRootNode();    parseTree->Traverse(generator);}

一直以来有实现一个简单的C编译器的想法,记录以上代码,留待以后使用。


原创粉丝点击