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); } }