The Façade Pattern
Of the 23 design patterns outlined in the GoF book, one I find myself reaching for time and time again is the façade pattern. In fact, I was making use of this design pattern before I even knew that the technique employed was called the façade pattern! Despite the fancy sounding name, both it's purpose and implementation are blessedly simple. It is used when it is necessary, or simply advantageous to "hide" a series of inter-connected but technically unrelated classes, by putting a public "face" over them. In this way the design pattern is often employed as a way of masking the use of multiple API's by presenting them as a single, unified API.
For example, the REPL of an interpreter during the course of execution might make use of several different components, such as a string buffer whos output is used for the input to a lexical analyzer. Likewise the output of the lexical analyzer is then used as the input to a parser, which ultimately produce's an Abstract Syntax Tree. If we were to forgo using the façade pattern, our client code must then explicitly interact with each individual sub system in turn. Performing the work of setting up the input and handling the output of each distinct component, making sure they are initialized and executed in the correct order, etc.
void repl() {
Lexer lexer;
Parser parser;
bool running = true;
while (running) {
string input;
getline(cin, input);
StringBuffer sb(input);
lexer = Lexer(sb);
SyntaxTree* ast = parser.parse(lexer.lex());
print(eval(ast));
}
}
Not only is this tedious, it opens up opportunities to introduce errors. It also makes the code harder to read, as we have to mentally track more "moving parts". Thankfully, there is a better way.
The Façade Pattern
If we know that our ultimate goal is to take the input string from the user and return an abstract syntax tree, then why must the client code need to know all of the details of the string buffer class, and the lexical analyzer class, and the parser class, their order of execution as well as individual API's? The façade pattern solves this issue by gathering all of the separate classes and abstracting their functionality into one unified ASTBuilder class. The ASTBuilder class has one public method that does exactly what the client code expects: takes an std::string as input, and returns a pointer to an Abstract Syntax Tree as it's output.
class ASTBuilder {
private:
StringBuffer sb;
Lexer lexer;
Parser parser;
public:
ASTBuilder() { }
SyntaxTree* makeAST(string input) {
sb = StringBuffer(input);
lexer = Lexer(sb);
return parser.parse(lexer.lex());
}
};
Like I mentioned above, its a magnificently straightforward design pattern. As you will see though, this simplicity has an outsized impact on how we use it when writing our client code. Now when we write our REPL, the client code need not worry about the how of the user input being converted into an AST. It's only concern is that the user input is turned into an AST. This has the advantage of not only greatly simplifying our client code from above, but the way the code reads also matches our intention more closely, making it easier overall both to read and maintain.
void repl() {
ASTBuilder astBuilder;
bool running = true;
while (running) {
string input;
getline(cin, input);
SyntaxTree* ast = builder.makeAST(input);
print(eval(ast));
}
}
As one of the senior software engineers I work with always says: "fewer lines, fewer bugs". And its some great advice. That's all I've got for today, so until next time Happy Hacking!
-
Digital Search Trees
-
Lossless Compression Part III: Huffman Coding
-
Lossless Compression Part II: The LZ77 Algorithm
-
Lossless Compression Part I: Working with Bits in a Byte Oriented World
-
Bottom Up AVL Tree: The OG Self-Balancing Binary Search Tree
-
A Different Take on Merge Sort: Binary Search Trees?
-
Deleting Entries From Open-Address Hash tables
-
Transform any Binary Search Tree in to a Sorted Linked List
-
From Regular Expressions To NFA by way of Abstract Syntax Trees: Thompsons Construction
-
Extending Sedgewick's explicit Digraph NFA
Leave A Comment