Design Pattern
Table of Contents
1 Creation
1.1 Abstract Factory
- Implemented by Factory Method.
- Focus on a family of products.
- ConcreteFactory is often singleton
abstract class AbstractFactory { + CreateA() + CreateB() } class ConcreteFactory1 { + CreateA(); + CreateB(); } class ConcreteFactory2 { + CreateA(); + CreateB(); } abstract class AbstractA abstract class AbstractB class A1 class A2 class B1 class B2 AbstractFactory<..ConcreteFactory1 AbstractFactory<..ConcreteFactory2 AbstractA<..A1 AbstractA<..A2 AbstractB<..B1 AbstractB<..B2 ConcreteFactory1*--A1 ConcreteFactory1*--B1 ConcreteFactory2*--A2 ConcreteFactory2*--B2
The implementation:
class AbstractFactory { virtual CreateA() {} virtual CreateB() {} }; class ConcreteFactory1 { virtual CreateA() {new A1;} virtual CreateB() {new B2;} }; class ConcreteFactory2 { virtual CreateA() {new A2;} virtual CreateB() {new B1;} }; // client code ConcreteFactory1 factory; AbstractA *a = factory.CreateA(); AbstractB *b = factory.CreateB();
1.2 Builder
1.2.1 Class Diagram
class Director { } Director <|-- Builder note right of Director: for all objects in structure { builder->BuildPart();} abstract class Builder { BuildPart(); } class ConcreteBuilder { BuildPart(); GetResult(); } Builder <-- ConcreteBuilder Product <.. ConcreteBuilder
1.2.2 Sequence diagram
participant Client participant Director participant ConcreteBuilder Client --> ConcreteBuilder : new ConcreteBuilder Client --> Director : new Director(concreteBuilder) Client --> Director : Construct() Director --> ConcreteBuilder : BuildPartA() Director --> ConcreteBuilder : BuildPartB() Director --> ConcreteBuilder : BuildPartC() Director --> ConcreteBuilder : GetResult()
1.2.3 Implementation
Director::Create() { builder.BuildPartA(); builder.BuildPartB(); builder.BuildPartC(); }; // client knows which concreteBuilder to use, // so it knows which the product is ConcreteBuilder builder; director = Director(builder); director.Create(); builder.GetResult();
2 Structure
2.1 Singleton
class Singleton { public: static Singleton* Instance() { if (m_instance == 0) { m_instance = new Singleton; } return m_instance; } protected: Singleton(); private: static Singleton* m_instance; }; Singleton *Singleton::m_instance = 0;
3 Behavior Pattern
3.1 Visitor pattern
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing theclasses of the elements on which it operates.
3.1.1 The problem and the naive solution
We have a list of classes in a class hierarchy, e.g. AST nodes. We want to define many operations, each operates different on different nodes.
abstract class Node { {abstract} TypeCheck(); {abstract} GenerateCode(); {abstract} PrettyPrint(); } class NumNode { TypeCheck(); GenerateCode(); PrettyPrint(); } class ExpNode class AddExpNode { TypeCheck(); GenerateCode(); PrettyPrint(); } Node <-- NumNode Node <-- ExpNode ExpNode <-- AddExpNode
This is not good. Application code is mixed with the AST node implementation.
3.1.2 The pattern
We define a hierarchy of visitors, and defines different behavior inside the visitors for different nodes they operate on. This is called double-dispatch: The virtual functions lookup is decided not only by the object the function is defined on, but also the arguments it accepts.
abstract class Node { {abstract} Accept(Visitor v); } class NumNode { Accept(Visitor v); } note left: v.visit(this); class ExpNode class AddExpNode { Accept(Visitor v); } note left: v.visit(this); Node <-- NumNode Node <-- ExpNode ExpNode <-- AddExpNode abstract class Visitor { {abstract} visit(NumNode node); {abstract} visit(AddExpNode node); } class TypeCheckVisitor { visit(NumNode node); visit(AddExpNode node); } class GenerateCodeVisitor { visit(NumNode node); visit(AddExpNode node); } class PrettyPrintVisitor { visit(NumNode node); visit(AddExpNode node); } Visitor <-- TypeCheckVisitor Visitor <-- GenerateCodeVisitor Visitor <-- PrettyPrintVisitor
3.1.3 Example
public interface AST { public static abstract class ASTNode { public abstract Object accept(Visitor visitor); } public static abstract class Exp extends ASTNode { } public static class NumExp extends Exp { double _val; public Object accept(Visitor visitor) { return visitor.visit(this); } } public static class AddExp extends CompoundArithExp { public AddExp(List<Exp> args) { super(args); } public Object accept(Visitor visitor) { return visitor.visit(this); } } }
public class Evaluator implements Visitor<Value> { public Value visit(NumExp e) { return new NumVal(e.v()); } public Value visit(AddExp e) { List<Exp> operands = e.all(); double result = 0; for (Exp exp : operands) { NumVal intermediate = (NumVal) exp.accept(this); // Dynamic // type-checking result += intermediate.v(); // Semantics of AddExp in terms of the // target language. } return new NumVal(result); } }