SlideShare a Scribd company logo
1 of 92
From Code to Pattern 
Understanding classical GoF patterns with C++
Agenda 
• Why this necessary 
• OO fundamental 
• OO in C++ 
• GoF classical pattern 
• Creational 
• Structural and behavioral 
• Inter-operational 
4:54:14 AM 
2
Why this necessary 
• Know what those terms mean on earth 
• Know how they work 
• Know why they came 
• Know how to connect to your daily work 
4:54:14 AM 
3
OO concepts 
Class 
4:54:14 AM 
4
OOD principles 
• Program to an interface, not an implementation 
• Favor object composition over class inheritance 
• SOLID 
• Single responsibility principle 
• A class exist only for one reason 
• Open/closed principle 
• Add a new feature through extend exist class instead of modify it 
• Liskov substitution principle 
• In all cases, subclass can substitute its parent without invalidate any 
desirable state 
• Interface segregation principle 
• Prefer specific interfaces than general purpose interface 
• Dependency inversion principle 
• Depends on abstract instead of high-level or low-level module 
4:54:14 AM 
5
How OOD works 
• Finding Appropriate Objects 
• Find the nouns in user case/scenario 
• Determining Object Granularity 
• Refine the noun if it can do complete unrelated things 
• Specifying Object Interfaces 
• Define what the object can do 
• Specifying Object Implementations 
• Define how the object does 
4:54:14 AM 
6
The core of OO 
• Type and class 
• Interface is the message it can handle 
• Type is interface set 
• Class is type implementation 
• A class may have(support) more types 
• Messaging 
• The sender 
• The receiver 
• The message 
• The message body 
• Inheritance relationship 
• “is-a”? 
• “has-a”? 
• “implement-a”? 
• Abstraction 
• Bind data and behaviors together 
• Hide as more as possible information 
4:54:14 AM 
7
The core of OO in C++ 
• Type and class 
• Interface is the message it can handle Virtual function in abstract class 
• Type is interface set Abstract class 
• Class is type implementation Concrete class 
• A class may have(support) more types Multiple inheritance class 
• Messaging 
• The sender None or implicit object 
• The receiver Named object 
• The message Named member method 
• The message body Parameters of member function 
• Inheritance relationship 
• “is-a”? Public inheritance from class 
• “has-a”? Private inheritance or object composition 
• “implement-a”? Public inheritance from type 
• Abstraction 
• Bind data and behaviors together Member variables and methods 
• Hide as more as possible information Access modifier 
4:54:14 AM 
8
The simplest case study 
• Set-and-call style 
// client end code 
void call() { 
Foo foo; 
foo.set_property("id", 100); 
foo.set_property("name", "wooooo"); 
foo.bar(); 
} 
• Try to identify the hardcode points 
• Some questions 
• How does an object get to create? 
• How does an object get to destroy? 
• How to send a message to an object? 
• How does the object handle a message? 
4:54:14 AM 
9
How can it be flexible? 
• Avoid hardcode! But what’s hardcode then? 
• Data hardcode 
• Hardcoded path, name, value etc. 
• Should be avoided always and easy to do 
• Structure hardcode 
• Fixed class implementation 
• Derivation relationship 
• Use a class name directly 
• Use a method name directly 
• Add an extra layer 
• Structure layer 
• Interactive layer 
• We get flexibility with the cost of complexity! 
• Be sensitive with tradeoff 
4:54:14 AM 
10
Design pattern, the definition 
• Wikipedia: “… is general reusable solution to a commonly occurring 
problem in software design” 
• GoF: “… names, abstracts, and identifies the key aspects of a 
common design structure that make it useful for creating a reusable 
object-oriented design” 
• Essential of DP 
• Specific name 
• Scenario 
• Solution 
• We are going to: 
• Show how simple codes are evolved and refactored to meet more 
requirements and 
• Show how GoF classify and name it 
• NOTE 
• The sample code does not care the delete of object. Just as object 
creation, there are patterns to handle object lifecycle, such as RAII. 
4:54:14 AM 
11
Objects creation 
4:54:14 AM 
12
How to get an object? I 
• You know the class name 
• Fully type information 
available only at compile-time 
• Stack based object 
• Pros 
• Straight 
• Easy to use 
• Map to language structure 
directly 
• Cons 
• Compile-time limitation 
• Scope based Lifecycle 
• Hardcoded type 
• Strict couple of server end 
code and client end code 
// server end code 
struct Foo { 
void bar() { cout << “bar calledn"; } 
}; 
struct Foo2 { 
void bar() { cout << “bar2 calledn"; } 
}; 
void bang(Foo* foo, Foo2* foo2) { 
foo->bar(); 
foo2->bar(); 
} 
// client end code 
void call() { 
Foo foo; 
Foo2 foo2 
bang(&foo, &foo2); 
} 
4:54:14 AM 
13
How to get an object? II 
• Heap based object 
• Pros 
• Long life across scope 
• Easy to use still 
• Map to language structure 
directly 
• Cons 
• Hardcoded type name 
• Still tightly coupling 
// server end code 
struct Foo { 
void bar() { cout << "bar calledn"; } 
}; 
struct Foo2 { 
void bar() { cout << "bar2 calledn"; } 
}; 
void bang(Foo* foo, Foo2* foo2) { 
foo->bar(); 
foo2->bar(); 
} 
// client end code 
Foo* get_foo() { return new Foo; } 
Foo2* get_foo2() { return new Foo2; } 
void call() { 
Foo* foo = get_foo(); 
Foo2* foo2 = get_foo2(); 
bang(foo, foo2); 
} 
4:54:14 AM 
14
How to get an object? III 
• First try of refactor 
• Abstract the interface 
• Server end code cares about the 
interface that Foo exposes 
instead of Foo object 
• Pros 
• Decouple server end code so that 
it’ll not depends on the Foo 
definition 
• Cons 
• New derivation layer 
• For any new implementation of 
IFoo interface, client end code 
must be modified 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
void bang(const vector<IFoo*> vf) { 
for_each(vf.begin(), vf.end(), 
mem_fun(&IFoo::bar)); 
} 
// client end code 
struct Foo : IFoo { 
virtual void bar() { cout << "bar calledn"; } 
}; 
struct Foo2 : IFoo { 
virtual void bar() { cout << "bar2 calledn"; } 
}; 
IFoo* get_foo() { return new Foo; } 
IFoo* get_foo2() { return new Foo2; } 
void call() { 
vector<IFoo*> vf; 
vf.push_back(get_foo()); 
vf.push_back(get_foo2()); 
bang(vf); 
} 
4:54:14 AM 
15
How to get an object? IV 
• Second try of refactor 
• Abstract the creation of object 
• Decouple server end code and 
client code completely 
• Pros 
• Easy to add new IFoo interface 
implementation without 
change server end and client 
end code 
• Server end code only define the 
interfaces and the business 
logics skeleton 
• Cons 
• Complex with double derivation 
layers 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct IFooCreater { 
virtual IFoo* create() = 0; 
}; 
void bang(IFooCreater* fc) { 
fc->create() ->bar(); 
} 
struct Foo : IFoo { 
virtual void bar() { cout << "bar calledn"; } 
}; 
struct Foo2 : IFoo { 
virtual void bar() { cout << "bar2 calledn"; } 
}; 
struct FooCreater : IFooCreater { 
enum FooType {TFoo, TFoo2} type_; 
FooCreater(FooType t) : type_(t) {} 
virtual IFoo* create() { 
if (type_ == TFoo) return new Foo; 
if (type_ == TFoo2) return new Foo2; 
assert(0); return 0; 
} 
}; 
void call() { 
bang(new FooCreater(FooCreater::TFoo)); 
bang(new FooCreater(FooCreater::TFoo2)); 
} 
4:54:14 AM 
16
The Factory Method 
• What’s that? The Factory method! 
• GoF: “Define an interface for creating an object, but let 
subclasses decide which class to instantiate. Factory Method 
lets a class defer instantiation to subclasses” 
4:54:14 AM 
17
How to get an object? I 
• You have no class name, but 
an existed object 
• Copy constructor? 
• Need to know the class of 
the object 
• RTTI? 
• Not fully typed information 
• There is no built-in support 
in C++! 
• The first try 
• Seems useless at all, I know 
it’s Foo here! 
• An incorrect user scenario 
// server end code 
class Foo { 
public: Foo* clone() { 
return new Foo(*this); 
} 
}; 
vector<Foo*> foos; 
void bang(Foo* f) { 
Foo* baby = f->clone(); 
// change some attributes 
foos.push_back(baby); 
} 
// client end code 
static Foo default_foo; 
void call() { 
bang(&default_foo); 
} 
4:54:14 AM 
18
How to get an object? II 
• The second try 
• Server end code should not 
care about the class of the 
object 
• Pros 
• Again, we move the concrete 
implementation to client end 
• Again, we can easily add new 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
virtual IFoo* clone() = 0; 
}; 
vector<IFoo*> foos; 
void bang(IFoo* f) { 
IFoo* baby = f->clone(); 
// change some attributes 
foos.push_back(baby); 
} 
// client end code 
class Foo : public IFoo { 
virtual Foo* clone() { 
return new Foo(*this); 
} 
virtual void bar() {} 
}; 
static Foo default_foo; 
void call() { 
bang(&default_foo); 
} 
4:54:14 AM 
19
The Prototype 
• What’s that? The prototype! 
• GoF: “Specify the kinds of objects to create using a prototypical 
instance, and create new objects by copying this prototype” 
• Dynamic languages don’t need this pattern as all type 
information are available on runtime 
4:54:14 AM 
20
How to get the object? I 
• In prototype sample, there is a default instance and all other 
copies are cloned from it. 
• And the instance should be global unique 
• Should not be constructed by user 
• Should be ready before the first use 
• Should be cleanup elegance 
• Had better never be constructed if it’s not be used 
• So 
1. Private constructor 
2. Runtime library constructed instance (conflict with 1) or 
runtime construct with condition 
3. Resource management 
4. Lazy-initialized 
4:54:14 AM 
21
How to get the object? II 
• The initial implementation 
• some issues 
• IFoo implementation is bond 
to server end and not easy 
to extend 
• Mixed functionalities of class 
FooSingleton: it implements 
both IFoo and singleton 
interface 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct FooSingleton : public IFoo { 
static IFoo* get_instance() { 
if (!instance_) 
instance_ = new FooSingleton; 
return instance_; 
} 
void bar() { cout << "bar calledn"; } 
private: 
FooSingleton() {} 
static IFoo* instance_; 
}; 
IFoo* FooSingleton::instance_ = 0; 
// client end code 
void call() { 
IFoo* foo = FooSingleton::get_instance(); 
foo->bar(); 
} 
4:54:14 AM 
22
How to get the object? III 
• The final try 
• Use another pattern we have 
not discussed (the bridge 
pattern) to avoid the cohesion 
between interface and 
implementation 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct IFooImpl { 
virtual void bar_impl() = 0; 
}; 
struct FooSingleton : public IFoo { 
static IFoo* get_instance(IFooImpl* impl) { 
if (!instance_) 
instance_ = new FooSingleton(impl); 
return instance_; 
} 
void bar() { impl_->bar_impl(); } 
private: 
FooSingleton(IFooImpl* i) : impl_(i) {} 
IFooImpl* impl_; 
static IFoo* instance_; 
}; 
IFoo* FooSingleton::instance_ = 0; 
// client end code 
struct MyImpl : IFooImpl { 
void bar_impl() { cout << "bar calledn"; } 
}; 
void call() { 
IFoo* foo = FooSingleton::get_instance(new MyImpl); 
foo->bar(); 
} 
4:54:14 AM 
23
The Singleton 
• What’s that? The singleton pattern! 
• GoF: “Ensure a class only has one instance, and provide a 
global point of access to it” 
• More discussion on singleton 
• Thread safety consideration 
• Dependency among singletons 
• Double-check idioms 
• Return reference instead of pointer 
4:54:14 AM 
24
How to get some objects? I 
• OK, we need some related or 
dependent objects 
• Same class? 
• Stack based object array or 
heap based dynamic object. 
Works only if the Foo has a 
default constructor. 
// client end code 
void same_class() { 
Foo foos1[100]; 
Foo* foos2 = new Foo[100]; 
vector<Foo> foos3(100); 
// cannot return foos1 
// had better avoid return foos3 
} 
4:54:14 AM 
25 
// 
// server end code, none
How to get some objects? II 
• Different class but same 
type? 
• Construct directly 
• Or use some factories 
// server end code 
strcut IFoo { 
virtual void bar() = 0; 
}; 
struct D1 : IFoo { 
virtual void bar() {...} 
}; 
struct D2 : IFoo { 
virtual void bar() {...} 
}; 
void bang(const vector<IFoo*>& fs) { 
for_each(fs.begin(), 
fs.end(), 
mem_fun(&IFoo::bar)); 
} 
// client end code 
void call() { 
vector<IFoo*> fs; 
fs.push_back(new D1); 
fs.push_back(new D2); 
bang(fs); 
} 
4:54:14 AM 
26
How to get some objects? III 
• Different type? 
• Cannot get a list of object 
that have no shared type 
• Instead, use a struct to warp 
them and make each object 
as a member and use them 
by name 
• Then, can you more specific? 
• Say, type1 and type2 can be 
subtyped both dynamically 
… 
struct package { 
type1 v1; 
type2 v2; 
// … 
}; 
void diff_type() { 
package p; 
// use(get/set) each member 
// can return if necessary 
} 
4:54:14 AM 
27 
// 
// server end code, none
How to get some objects? IV 
• Let’s have a try 
• Reconsider the scenario, we 
are building a C language 
compiler front end skeleton, 
and it includes preprocessor 
and assembler. 
• How can we support 
another language, say C++, 
while will not affect the 
server end code? 
// server end code 
struct front_end { 
preprocesser* pp_; 
assembler* as_; 
void compile(string file) { 
as_->doit(pp_->doit(file)); 
} 
}; 
void do_compile(string file) { 
front_end* fe = new front_end; 
fe->pp_ = new preprocesser; 
fe->as_ = new assembler; 
fe->compile(file) 
} 
// client end code 
void call() { 
do_compile("hello.c"); 
} 
4:54:14 AM 
28
How to get some objects? V 
• Refactor it so that it can 
easy support more 
language 
• Abstract interface of 
preprocess and assemble, 
push the implementation 
to client end. 
// server end code 
struct IPreprocesser { 
virtual string doit(string f) = 0; 
}; 
struct IAssemble { 
virtual string doit(string f) = 0; 
}; 
struct IFront_end_creator { 
virtual IPreprocesser* create_pp() = 0; 
virtual IAssemble* create_as() = 0; 
}; 
class front_end { 
IPreprocesser* pp_; 
IAssemble* as_; 
public: 
front_end(IFront_end_creator* c) { 
pp_ = c->create_pp(); 
as_ = c->create_as(); 
} 
void compile(string file) { 
as_->doit(pp_->doit(file)); 
} 
}; 
4:54:14 AM 
29
How to get some objects? VI 
• The client code for C (right) 
• The client code for C++ (below) 
// client end code: C front end 
struct CPreprocess : IPreprocesser { 
virtual string doit(string f) { return f; } 
}; 
struct CAssembale : IAssemble { 
virtual string doit(string f) { return f; } 
}; 
struct Cfe : IFront_end_creator { 
virtual IPreprocesser* create_pp(){ 
return new CPreprocess; 
} 
virtual IAssemble* create_as() { 
return new CAssembale; 
} 
}; 
// Client end code: C++ front end 
struct CPPPreprocess : IPreprocesser { 
virtual string doit(string f) { return f; } 
}; 
struct CPPAssembale : IAssemble { 
virtual string doit(string f) { return f; } 
}; 
struct CPPfe : IFront_end_creator { 
virtual IPreprocesser* create_pp() { 
return new CPPPreprocess; 
} 
virtual IAssemble* create_as() { 
return new CPPAssembale; 
} 
}; 
// client end code, how to use 
void call() { 
front_end cfe(new Cfe); 
fe.compile("hello.c"); 
front_end cppfe(new CPPfe); 
fe.compile("hello.cpp"); 
} 
4:54:14 AM 
30
The Abstract Factory 
• A little complex, let’s summary what we did by now 
• A derivation layer that create some related objects (IFront_end_creater) 
• An object that depends on the creator to create objects of another derivation 
layers (IPreprocesser and IAssemble) 
• What’s this? The Abstract Factory! 
• GoF: “Provide an interface for creating families of related or dependent 
objects without specifying their concrete classes” 
4:54:14 AM 
31
How get an object from data? I 
• Do you mean object serialization 
and deserialization? 
• Almost, but how? 
• so we have ... 
• Note, not clear boundary between 
server and client. 
• This is the simplest case and 
cannot fit complex scenarios such 
as the member is a point to some 
type 
• C++ has no reflect mechanism so 
that we save type information to 
file directly and then we can 
construct an object from it directly 
• Overriding works only if the 
concrete object is ready, but we 
have no yet. Chicken or eggs, eh? 
struct record { 
int id_; 
string name_; 
void serialize(ostream& os) { 
os << id_; 
os << name_ << endl; 
} 
void deserialize(istream& is) { 
is >> id_; 
is >> name_; 
} 
}; 
void call() 
{ 
record r; 
ifstream ifs("/root/data"); 
r.deserialize(ifs); 
} 
4:54:14 AM 
32
How get an object from data? II 
• Assume we are going to 
serialize front_end object and 
we only check the process of 
deserializing. 
• In order to get the class of 
concrete object, we must save 
the information as well as 
object data. So 
• each class derived from 
serializer should have a static 
global unique ID 
• we should serialize the ID 
before the object data 
• The next question is: where 
does the relationship between 
ID and class exist? 
• we need another helper type! 
// server end code 
struct serializer { 
virtual void save(ostream& os) = 0; 
virtual void load(istream& is) = 0; 
}; 
struct IPreprocesser : serializer { 
virtual string doit(string f) = 0; 
}; 
struct IAssemble : serializer { 
virtual string doit(string f) = 0; 
}; 
class front_end : serializer { 
IPreprocesser* pp_; 
IAssemble* as_; 
public: 
virtual void save(ostream& os) { 
pp_.save(os); 
as_.save(os); 
} 
virtual void load(istream& is) { 
// ?? 
} 
}; 
4:54:14 AM 
33
How get an object from data? III 
• The help class will help construct 
correct concrete object according 
the object ID. 
• Server end code first get the 
object via helper and than load it 
// server end code 
struct front_end : serializer { 
IPreprosseser* pp_; 
IAssemble* as_; 
ILoader* loader_; 
virtual void save(ostream& os) { 
os << pp_->id() << endl; 
pp_->save(os); 
os << as_->id() << endl; 
as_->save(os); 
} 
virtual void load(istream& is) { 
string pp_id, as_id; 
is >> pp_id; 
pp_ = loader_->get_pp(pp_id); 
pp_->load(is); 
is >> as_id; 
as_ = loader_->get_as(as_id); 
as_->load(is); 
} 
}; 
// server end code 
struct serializer { 
virtual string id() const = 0; 
virtual void save(ostream&) = 0; 
virtual void load(istream&) = 0; 
}; 
struct IPreprosseser : serializer {}; 
struct IAssemble : serializer {}; 
struct ILoader { 
virtual IPreprosseser* 
get_pp(string) = 0; 
virtual IAssemble* 
get_as(string) = 0; 
}; 
4:54:14 AM 
34
How get an object from data? IV 
• Client end provides the 
implementation of the helper 
class and specify different ID 
for different class. 
struct Front_end_loader : ILoader { 
virtual IPreprosseser* get_pp(string id) { 
if (id == CPreprocess::uuid) 
return new CPreprocess; 
else if (id == CPPPreprocess::uuid) 
return new CPPPreprocess; 
else throw "invalid preprocesser class id"; 
} 
virtual IAssemble* get_as(string id) { 
if (id == CAssemble::uuid) 
return new CAssemble; 
else if (id == CPPAssemble::uuid) 
return new CPPAssemble; 
else throw "invalid assemble class id"; 
} 
}; 
// C front end implementation code 
struct CPreprocess : IPreprocesser { 
static string uuid; 
virtual string id() const { return uuid; } 
virtual void save(ostream& os) const {} 
virtual void load(istream& is) {} 
}; 
string CPreprocess::uuid = "CPreprocess"; 
struct CAssemble : IAssemble { 
static string uuid; 
virtual string id() const { return uuid; } 
virtual void save(ostream& os) const {} 
virtual void load(istream& is) {} 
}; 
string CAssemble::uuid = "CAssemble"; 
void call() 
{ 
const char* file = "C:test.dat"; 
Front_end_loader loader; 
front_end fe(&loader); 
bk.load(ifstream(file)); 
} 
4:54:14 AM 
35
The Builder 
• We get running codes which satisfy following requirements 
• Type based serialization/deserialization 
• Easy to add new subtype without need modify the server end code 
• Focus on the part of loading. What’s that? The Builder Pattern! 
• GoF: “Separate the construction of a complex object from its 
representation so that the same construction process can create 
different representations” 
4:54:14 AM 
36
Sidebar: resource management 
• We ignore the issue of resource management at all in previous 
discussion 
• There is no default GC support in C++, but we have an elegant 
alternative, that’s RAII based resource management policy 
• Put it simple, use std::shared_ptr or std::unique_ptr always for 
all places that need a raw pointer 
• For other non-pointer resource, such as kernel object handle, 
locker, database connection, network connection etc., use RAII 
plus reference counted wrapper if need. 
• This is a big and serious topic and we need talk it separately. 
4:54:14 AM 
37
Sending a message 
4:54:14 AM 
38
The object and its behaviors 
• Object 
• Object type. The message set the object accepts. 
• Object class. The implementation of object types plus data that 
represent object status. 
• Object Id. The unique identifier of any object. 
• For C++ language level object, it’s memory address of the object 
• That is why objects of zero size class have different address 
• Object behavior: how the object handle a message 
• Object status decide the behaviors of it 
• Those behaviors that do not depend on status are static 
behaviors and will not be discussed here 
• How to change an object? 
• Set object status directly 
• Call a r/w behavior of object 
4:54:14 AM 
39
Send a message to object 
• Review C++ syntax of sending a message 
• Null or implicit caller 
• Directly depends on the detailed concrete object or a pointer to a type 
• Hardcoded message name, the member function name 
• Hardcoded massage property, the argument of the operation 
• The message is taken action at once 
• In C++, the sender is null (in global function, class static member 
function) or implicitly (in class member function). 
• Depends on the type implementation, C++ runtime will route the 
message to correct concrete object. 
• That’s polymorphism. 
• C++ runtime only cares about the target object 
• What if you want to routine the message by not only the type of target 
but the type of source? 
• That’s called double dispatch 
• Switch/case? Be a respectful programmer and forget it! 
4:54:14 AM 
40
Double dispatch I 
• Target uses C++ override mechanism 
to distinguish different source class 
and transfer the message back to 
source, the first dispatch. 
• Source uses C++ overload mechanism 
to distinguish different target class, 
the second dispatch. 
• We have follow initial implementation 
// server end code 
struct Source; 
struct Target { virtual void m(Source*) = 0; }; 
struct T1 : Target {virtual void m(Source* s); }; 
struct T2 : Target { virtual void m(Source* s); }; 
struct Source { 
virtual void m(T1*) = 0; 
virtual void m(T2*) = 0; 
}; 
struct S1 : Source { 
virtual void m(T1* t) { cout << "S1->T1n"; } 
virtual void m(T2* t) { cout << "S1->T2n"; } 
}; 
struct S2 : Source { 
virtual void m(T1* t) { cout << "S2->T1n"; } 
virtual void m(T2* t) { cout << "S2->T2n"; } 
}; 
void T1::m(Source* s) { s->m(this); } 
void T2::m(Source* s) { s->m(this); } 
// client end code 
void call() 
{ 
Source* s1 = new S1; 
Source* s2 = new S2; 
Target* t1 = new T1; 
Target* t2 = new T2; 
t1->m(s1); 
t1->m(s2); 
t2->m(s1); 
t2->m(s2); 
} 
4:54:14 AM 
41
Double dispatch II 
• Message m for target is only for exposing 
itself so that source can do more. That is, 
it accepts that object and transfer the 
control back to the object, so we rename 
the message as “accept” 
• Message m for source is the actually place 
we can handle different target type. It 
provides all possible target type overloads 
and visit them respectively, so we rename 
the message as “visit” 
• Meanwhile, the type source provides all 
possible overloads of derived class of type 
Target. That means it can walk the class 
hierarchy of type Target. So we rename is 
as “Visitor” 
• Finally, we get following codes. 
• What is it? 
• It provides the possible that add new 
operation to an existed class hierarchy. 
• The Visitor class is strong bound to 
Target class and any change of the Target 
class hierarchy will cause the change of 
Visitor interface. 
// server end code 
struct Visitor; 
struct Target { 
virtual void accept(Visitor*) = 0; 
}; 
struct T1 : Target { 
virtual void accept(Visitor* s); 
}; 
struct T2 : Target { 
virtual void accept(Visitor* s); 
}; 
struct Visitor{ 
virtual void visit(T1*) = 0; 
virtual void visit(T2*) = 0; 
}; 
void T1::accept(Visitor* s) { s->visit(this); } 
void T2::accept(Visitor* s) { s->visit(this); } 
4:54:14 AM 
42
The Visitor 
• What’s this? It’s Visitor pattern! 
• GoF: “Represent an operation to be performed on the elements of 
an object structure. Visitor lets you define a new operation without 
changing the classes of the elements on which it operates.” 
4:54:14 AM 
43
Send a message to an object 
• Review C++ syntax of 
sending a message 
• Null or implicit caller 
• Directly depends on the 
detailed concrete object or 
a pointer to a type 
• Hardcoded message name, 
the member function name 
• Hardcoded massage 
property, the argument of 
the operation 
• The message is taken action 
at once 
• How can it possible to erase 
those? 
4:54:14 AM 
44 
//serve end code 
struct Target { 
void foo() { cout << "Target::foo calledn"; } 
}; 
// client end code 
void call() { 
Target t; 
t.foo(); 
}
Indirect messaging I 
• Use an indirect layer to 
wrapper the message target 
• Binding the message name 
to the wrapped message 
target 
//serve end code 
struct Target; 
struct Wrapper { 
typedef void (Target::*Action)(); 
Target* t_; 
Action a_; 
Wrapper(Target* t, Action a) : t_(t), a_(a) {} 
void call() const { (t_->*a_)(); } 
}; 
struct Target { 
void foo() { cout << "Target::foo calledn"; } 
}; 
// client end code 
void call() { 
Target t; 
Wrapper w(&t, &Target::foo); 
w.call(); 
} 
4:54:14 AM 
45
Indirect messaging II 
• Try to refactor it 
• Programming for interface 
• Const correctness 
• Use template to support 
multiple concrete classes 
// serve end code 
struct IWrapper { 
virtual void call() const= 0; 
}; 
template <typename T> 
struct Wrapper : IWrapper { 
typedef void (T::*Action)(); 
T* t_; 
Action a_; 
Wrapper(T* t, Action a) : t_(t), a_(a) {} 
virtual void call() const { (t_->*a_)(); } 
}; 
// client end code 
struct Target{ 
void foo() { cout << "Target::foo calledn"; } 
} t; 
struct Another { 
void bar() { cout << "Another::foo calledn"; } 
} a; 
void call() { 
vector<IWrapper*> vw; 
vw.push_back( 
new Wrapper<Target>(&t, &Target::foo)); 
vw.push_back( 
new Wrapper<Target>(&a, &Another::foo)); 
for_each(vw.begin(), vw.end(), 
mem_fun(&IWrapper::call)); 
} 
4:54:14 AM 
46
The Command 
• What do we get? The Command pattern! 
• GoF: “Encapsulate a request as an object, thereby letting you 
parameterize clients with different requests, queue or log 
requests, and support undoable operations” 
• Question 
• How to support undo with this pattern? 
4:54:14 AM 
47
Broadcast a message 
• With native C++ support, we can only send one message to 
one object once. 
• How can we send a message to some objects? 
• Loop on the object array/list/tree? 
4:54:14 AM 
48
Message broadcasting I 
• In order to broadcast a 
message, we need 
• The message to be 
broadcasted 
• The target objects and they 
must can handle the message 
• An very native implementation 
//serve end code 
struct Target1 { 
void foo() const { } 
}; 
struct Target2 { 
void foo() const { } 
}; 
struct Broadcaster { 
Target1 t1_; 
Target1 t2_; 
void broadcast() { 
t1_.foo(); 
t2_.foo(); 
} 
}; 
// client end code 
void call() { 
Broadcaster b; 
b.broadcast(); 
} 
4:54:14 AM 
49
Message broadcasting II 
• Refactor actions 
• Abstract the unique interface 
• Push code to client 
• Dynamic target objects 
//serve end code 
struct ITarget { 
virtual void foo() const = 0; 
}; 
struct Broadcaster { 
vector<ITarget*> ts_; 
void broadcast() { 
for_each(ts_.begin(), ts_.end(), 
mem_fun(&ITarget::foo)); 
} 
void AddTarget(ITarget* t) { 
ts_.push_back(t); 
} 
}; 
// client end code 
struct Target1 : ITarget { 
virtual void foo() const { } 
}; 
struct Target2 : ITarget { 
virtual void foo() const { } 
}; 
void call() { 
Broadcaster b; 
b.AddTarget(new Target1); 
b.AddTarget(new Target2); 
b.broadcast(); 
} 
4:54:14 AM 
50
Message broadcasting III 
• It’s possible that the 
broadcaster itself will 
broadcast something if its state 
changes 
• Provides subscribe & 
unsubscribe interface 
• Callback to all subscribers if 
something occurs 
//serve end code 
struct ITarget { 
virtual void foo() const = 0; 
}; 
struct Broadcaster { 
vector<ITarget*> ts_; 
void broadcast() { 
for_each(ts_.begin(), ts_.end(), 
mem_fun(&ITarget::foo)); 
} 
void subscribe(ITarget* t) { 
ts_.push_back(t); 
} 
void unsubscribe(ITarget* t) { 
ts_.remove(t); 
} 
}; 
4:54:14 AM 
51
The Observer 
• What’s that? The Observer pattern! 
• GoF: “Define a one-to-many dependency between objects so 
that when one object changes state, all its dependents are 
notified and updated automatically” 
4:54:14 AM 
52
Send a message to someone 
• OO always requires specific target, sometimes it’s rigorous 
• The target is unknown on sending time (distributed environment) 
• The sender does not care who will handle it 
• There are maybe some policies to control what target will handle 
the message (load balance) 
• The target objects may have different priority to handle such 
message 
• How can it possible? 
• All problems in computer science can be solved by another level 
of indirection. So we need a gateway to get the message at first. 
• Meanwhile, we also need routine the message to other if itself 
cannot handle it, so we need chains them together 
4:54:14 AM 
53
Uncertain handler I 
• First try 
• Use a gateway class as the 
intermediate layer 
• Return if any handler 
handles the message 
• Some problems 
• Strong relationship of 
gateway class and concrete 
handlers. Difficult to adjust 
the order of handler 
• Cannot represent the 
relationship among 
handlers, they are all at the 
same level 
// server end code 
struct IFoo { 
virtual void bar(int) const = 0; 
virtual bool is_care(int) const = 0; 
}; 
struct gateway : IFoo { 
vector<IFoo*> fs_; 
mutable bool handled_ = false; 
virtual void bar(int n) const { 
for (size_t i = 0; i < fs_.size(); ++i) { 
if (fs_[i]->is_care(n)) { 
fs_[i].bar(n); 
break; 
} 
} 
} 
virtual bool is_care(int) const { return false; } 
void add_handler(IFoo* i) { fs_.push_back(i); } 
}; 
4:54:14 AM 
54
Uncertain handler I, Cont 
• Code at call site 
// client end code 
struct zero_handler : IFoo { 
virtual void bar(int) const { 
cout << "zero handlern"; } 
virtual bool is_care(int n) const { 
return n == 0; } 
}; 
struct odd_handler : IFoo { 
virtual void bar(int) const { 
cout << "odd handlern"; } 
virtual bool is_care(int n) const { 
return n && n%2 != 0; } 
}; 
struct even_handler : IFoo { 
virtual void bar(int) const { 
cout << "even handlern"; } 
virtual bool is_care(int n) const { 
return n && n%2 == 0; } 
}; 
4:54:14 AM 
55 
// client end code 
void call() { 
gateway gw; 
gw.add_handler(new odd_handler); 
gw.add_handler(new even_handler); 
gw.add_handler(new zero_handler); 
gw.bar(7); 
gw.bar(12); 
gw.bar(0); 
}
Uncertain handler II 
• Second try 
• Using a link structure 
• If one handler does not care 
this message, it will routine 
the message to its successor if 
there is 
// server end code 
struct IFoo { 
virtual void bar(int) const = 0; 
}; 
struct IChainFoo : IFoo { 
IFoo* next_; 
explicit IChainFoo(IChainFoo* next = 0) : 
next_(next) {} 
virtual bool is_care(int n) const = 0; 
virtual void bar_impl() const = 0; 
virtual void bar(int n) const { 
if (is_care(n)) 
bar_impl(); 
else if (next_) 
next_->bar(n); 
} 
}; 
// client end code 
// concrete handle implementation ignored 
void call() { 
IChainFoo* chain = new odd_handler( 
new zero_handler( 
new even_handler())); 
chain->bar(7); 
chain->bar(12); 
chain->bar(0); 
} 
4:54:14 AM 
56
The chain of responsibility 
• What’s that of linked message handling? The chain of 
responsibility pattern! 
• GoF: “Avoid coupling the sender of a request to its receiver by 
giving more than one object a chance to handle the request. 
Chain the receiving objects and pass the request along the 
chain until an object handles it” 
4:54:14 AM 
57
Load elephant into icebox I 
• The very old story, how can you 
load an elephant into a 
refrigerator? Three steps! 
• Open the door 
• Load the elephant 
• Close the door 
• We have right initial draft 
• Some comments 
• Foo defines the steps by 
implement bar() interface 
while providing default 
implementation (violate SRP) 
• Difficult to extend 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct Foo : IFoo { 
void open_refrigerator() { 
cout << "open very big one ...n"; 
} 
void load_elephant() { 
cout << "load the elephant if it willn"; 
} 
void close_refrigerator() { 
cout << "close itn"; 
} 
virtual void bar() { 
open_refrigerator(); 
load_elephant(); 
close_refrigerator(); 
} 
}; 
// client end code 
void call() { 
IFoo* foo = new Foo; 
foo->bar(); 
} 
4:54:14 AM 
58
Load elephant into icebox II 
• Refactor it to: 
• Push the implementation to client 
• Decouple the definition and 
implementation 
• So we have 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct IFooImpl { 
virtual void open_refrigerator() = 0; 
virtual void load_elephant() = 0; 
virtual void close_refrigerator() = 0; 
}; 
struct Foo : IFoo { 
IFooImpl* impl_; 
explicit Foo(IFooImpl* i) : impl_(i) {} 
virtual void bar() { 
open_refrigerator(); 
load_elephant(); 
close_refrigerator(); 
} 
}; 
// client end code 
struct MySolution : IFooImpl { 
void open_refrigerator() { 
cout << "open very big one ...n"; 
} 
void load_elephant() { 
cout << "load the elephant if it willn"; 
} 
void close_refrigerator() { 
cout << "close itn"; 
} 
}; 
void call() { 
IFoo* foo = new Foo(new MySolution); 
foo->bar(); 
} 
4:54:14 AM 
59
The template method 
• What’s that of base class defines skeleton while derived class 
provides implementation? The template method pattern! 
• GoF: “Define the skeleton of an algorithm in an operation, deferring 
some steps to subclasses. Template Method lets subclasses redefine 
certain steps of an algorithm without changing the algorithm's 
structure” 
• Our example is a little different with the default structure as we 
push the implementation to client end 
• Similar to Bridge pattern but with different intent. 
4:54:14 AM 
60
Handling message 
4:54:14 AM 
61
Handle message directly I 
• As behaviors of an object are 
decided by its state, so there 
is a typical implementation. 
• Possible issues 
• Difficult to extend. If we 
want to do something 
special action for state 4, we 
must modify the Foo 
implementation 
• Had better avoid 
switch/case or if/else if/else 
structure 
• Indeed, an actually bug 
there! 
// server end code 
struct Foo { 
int state_; 
void do_one() { cout << “action onen”; } 
void do_two() { cout << “action twon”; } 
void do_infinity() { cout << “action infinityn”; } 
void set(int s) { state_ = s; } 
void bar() { 
switch(state_) { 
case 1: do_one(); 
case 2: do_two(); 
default: do_infinity(); 
} 
} 
}; 
// client end code 
void call() { 
Foo foo; 
foo.set(2); 
foo.bar(); 
} 
4:54:14 AM 
62
Handle message directly II 
• Refactor 
• Server end codes are written 
for interface only 
• Push actually functional 
codes to client end 
• Avoid switch/case by strong 
type 
// server end code 
struct IFoo_action { 
virtual void do_action() = 0; 
}; 
struct Foo { 
IFoo_action* action_; 
void set_action(IFoo_action* a) { action_ = a; } 
void bar() { action_->do_action(); } 
}; 
// client end code 
struct Action_for_one : IFoo_action { 
void do_action() { cout << "action onen"; } 
}; 
struct Action_for_two : IFoo_action { 
void do_action() { cout << "action twon"; } 
}; 
struct Action_for_infinity : IFoo_action { 
void do_action() { cout << "action infinityn"; } 
}; 
// client end code 
void call() { 
Foo foo; 
foo.set_action(new Action_for_two); 
foo.bar(); 
} 
4:54:14 AM 
63
The strategy 
• What’s that? The strategy pattern! 
• GoF: “Define a family of algorithms, encapsulate each one, 
and make them interchangeable. Strategy lets the algorithm 
vary independently from clients that use it” 
4:54:14 AM 
64
Enhance message handling I 
• There is an existed 
implementation of some 
types and you want to: 
• Reuse the implementation 
• Enhancement some specific 
behaviors, such as log, 
authentication, lock/unlock 
etc 
• The initial try is as right 
• Drawbacks 
• How about LSP? 
• Difficult to extend 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
virtual void baz() = 0; 
}; 
struct Foo : IFoo { 
void bar() { cout << "action barn"; } 
void baz() { cout << "action bazn"; } 
}; 
// client end code 
void do_log(const char* msg) { 
cout << msg << "n"; 
} 
void call() { 
Foo foo; 
do_log("before call bar"); 
foo.bar(); 
} 
4:54:14 AM 
65
Enhance message handling II 
• What does LSP say: 
• Wiki : “if S is a subtype of T, 
then objects of type T … may 
be replaced with objects of 
type S (i.e., objects of type S 
maybe substituted for objects 
of type T), without altering 
any of the desirable 
properties of that program 
(correctness, task performed, 
etc.)” 
• Now we can treat the Foo 
object and our customized 
MyFoo object in the same 
way 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct Foo : IFoo { 
void bar() { cout << "action barn"; } 
}; 
// client end code 
void do_log(const char* msg) { 
cout << msg << "n"; 
} 
struct MyFoo : Foo { 
void bar() { 
do_log("before call bar"); 
Foo::bar(); 
} 
}; 
void call() { 
vector<IFoo*> vfs; 
vfo.push_back(new Foo); 
vfo.push_back(new MyFoo); 
for_each(vfs.begin(), vfs.end(), 
mem_fun(&IFoo::bar)); 
} 
4:54:14 AM 
66
The decorator 
• What’s that? The decorator pattern! 
• GoF: “Attach additional responsibilities to an object 
dynamically. Decorators provide a flexible alternative to 
subclassing for extending functionality” 
4:54:14 AM 
67
Delegated message handling 
• Sometime, creating an 
object has a big overhead or 
just impossible 
• A distributed object maybe 
resident on another address 
space, so we need RPC 
infrastructure as the basis. 
• You have the right to use it 
only 
• Creating and destroying such 
object often is not desirable 
4:54:14 AM 
68
The proxy (TODO) 
• What’s that? The proxy pattern! 
• GoF: “Provide a surrogate or placeholder for another object to 
control access to it” 
• Remote proxy. For distributed OO system 
• Virtual proxy. For lazy loading or initialization 
• Protected proxy. For access control 
• Smart pointer. For resource management or verification 
4:54:14 AM 
69
The state (TODO) 
• What’s that? The state pattern! 
• GoF: “Allow an object to alter its behavior when its internal 
state changes. The object will appear to change its class” 
4:54:14 AM 
70
Separated object serialize (I) 
• Image a ring buffer 
implementation 
• It gets store from client 
• It manipulates the buffer 
• Question: how to serialize the 
ring buffer object? 
• Answer one: serialize the buffer 
also 
• Bad solution. Client may have 
done this. Duplication! 
• Answer two: just serialize 
front/back status 
• Not good enough yet. After 
deserialized, the object status 
is not complete. 
4:54:14 AM 
71 
// server end code 
struct RingBuffer { 
explicit RingBuffer(char* buff, size_t sz) 
: _size(sz), _buff(buff), _front(0), _back(_buff) 
{} 
void push_back(char value) { … } 
private: 
size_t _size; 
char* _buff; 
char* _front 
char* _back; 
}; 
// client end code 
void call() { 
char buff[1024]; 
RingBuffer rb(buff, 1024); 
const char* msg = “hello world!”; 
std::copy(msg, msg + strlen(msg), 
std::back_inserter<RingBuffer>(rb)); 
}
Separated object serialize (II) 
• Answer three: delegate the 
serialization task client fully 
• Save internal status to a 
Memo object 
• Client can save this object 
• Client can restore this object 
later 
• Will 
4:54:14 AM 
72 
// server end code 
struct RingBuffer { 
explicit RingBuffer(char* buff, size_t sz) {…} 
void push_back(char value) { … } 
struct Memo { 
size_t _sz; 
size_t _off; 
Memo(size_t sz, size_t off) : _sz(sz), _off(off) {} 
}; 
Memo* create_memo() const {…} 
void set_memo(Memo* m) {…} 
};
The memento (TODO) 
• What’s that? The memento pattern! 
• GoF: “Without violating encapsulation, capture and 
externalize an object's internal state so that the object can be 
restored to this state later” 
4:54:14 AM 
73
Object relationship 
4:54:14 AM 
74
The adapter 
• What’s that? The adapter pattern! 
• GoF: “Convert the interface of a class into another interface 
clients expect. Adapter lets classes work together that 
couldn't otherwise because of incompatible interfaces” 
4:54:14 AM 
75
Special object including I 
• Many times, the object and its owner same type, that is, 
they implement the same interface and can be used 
interchangeable 
• File system. A folder can includes folders and files and they are 
all file system objects 
• Windows system. A dialog may include some buttons, edit 
boxes, combos etc. they are all windows indeed. 
• Image following client codes 
// client end code 
void call() { 
Dialog* dia = new Dialog("type your password"); 
dia->attach(new Button("OK")); 
dia->attach(new Button("Cancel")); 
dia->attach(new EditBox("Edit here")); 
dia->enable(); 
} 
4:54:14 AM 
76
Special object including II 
// server end code 
struct IWin{ 
std::string name_; 
virtual void enable() = 0; 
// more windows properties 
}; 
struct Button : IWin{ 
Button(const char* name) { name_ = name; } 
void enable() { cout << "Button " << name_ << endl; } 
}; 
struct EditBox : IWin{ 
EditBox(const char* name) { name_ = name; } 
void enable() { cout << "EditBox " << name_ << endl; } 
}; 
struct Dialog : IWin{ 
Dialog(const char* name) { name_ = name; } 
void attach(IWin* w) { wins_.push_back(w); } 
void enable() { 
for_each(wins_.begin(), wins_.end(), 
mem_fun(&IWin::enable)); 
cout << "Dialog "" << name_ <<"" enablen"; 
} 
list<IWin*> wins_; 
}; 
• And this is the server end 
code 
• All concrete classes 
implement the same type 
• If one of them to be a 
container, it contains a 
list of pointer to that type 
• On message handling, 
before/after its own 
handling mechanism, it’ll 
forward the message to 
all objects it contains 
4:54:14 AM 
77
The composite 
• What’s that? The composite pattern! 
• GoF: “Compose objects into tree structures to represent part-whole 
hierarchies. Composite lets clients treat individual objects and 
compositions of objects uniformly” 
• The pattern is seldom used alone, some other pattern make it more 
useful 
• Visitor. Add extra functionality to the class struct 
• Iterator. Enumerate and manipulate each subobjects 
• … 
4:54:14 AM 
78
Interface implementation 
4:54:14 AM 
79
Implementation an interface I 
• Simple and straight, C++ 
provides directly support 
• There is a very big limitation 
however 
• The implementation is bond 
to server end code and 
change the implementation 
will definitely change server 
end code 
• How can we remove it? 
• Add new indirection layer 
• Push responsibility to client 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct Foo : IFoo { 
void bar() { cout << "IFoo implementedn"; } 
}; 
// client end code 
void call() { 
Ifoo* foo = new Foo; 
foo->bar(); 
} 
4:54:14 AM 
80
Implementation an interface II 
• Distinguish the type for interface and 
the type for implementation 
• Client end will provides the concrete 
implementation while server end 
only care about the interface to 
implementation 
• C++ usually calls this as p-impl idiom 
and use it to eliminate the strong 
header including relationship 
// server end code 
struct IFoo { 
virtual void bar() = 0; 
}; 
struct IFooImpl { 
virtual void bar_impl() = 0; 
}; 
struct Foo : public IFoo { 
IFooImpl* impl_; 
Foo(IFooImpl* i) : impl_(i) {} 
void bar() { impl_->bar_impl(); } 
}; 
// client end code 
struct MyImpl : public IFooImpl { 
virtual void bar_impl() { 
cout << "my IFoo implementationn"; } 
}; 
struct MyImplv2 : public IFooImpl { 
virtual void bar_impl() { 
cout << "my IFoo implementation v2n"; } 
}; 
void call() { 
vector<IFoo*> vf; 
vf.push_back(new Foo(new MyImpl)); 
vf.push_back(new Foo(new MyImplv2)); 
for_each(vf.begin(), vf.end(), 
mem_fun(&IFoo::bar)); 
} 
4:54:14 AM 
81
The bridge 
• What’s that? The bridge pattern! 
• GoF: “Decouple an abstraction from its implementation so 
that the two can vary independently” 
4:54:14 AM 
82
Interface management 
4:54:14 AM 
83
Using a package I 
• Usually, we use some classes of 
a package to do something 
• Typical, it’s the case that 
exporting some APIs for 3rd 
part use 
• Pitfalls 
• Sometimes you may not want 
expose the details of internal 
interfaces of server end code 
to client 
• Meanwhile, you don’t want to 
hide something that hard to 
use correctly or secrets 
• Client end code depends on 
the internal components of 
server end code, which make 
it’s very difficult to change 
server end implementation 
// server end code 
namespace domain { 
struct Foo { 
void do_foo() { cout << "Foo usedn"; } 
}; 
struct Bar { 
void do_bar() { cout << "Bar usedn"; } 
}; 
struct Baz { 
void do_baz() { cout << "Baz usedn"; } 
}; 
} 
// client end code 
void call() { 
domain::Foo f; 
domain::Bar b; 
domain::Baz z; 
f.do_foo(); 
b.do_bar(); 
z.do_baz(); 
} 
4:54:14 AM 
84
Using a package II 
• Refactor it 
• Add another layer 
• Provide a new interface and 
standard the implementation of 
such common used tasks 
• The original interfaces may or 
may not available to client codes, 
depends on how your codes are 
used by client you expect 
• Client end code will not continue 
care about how the interfaces 
are implemented. They only use 
them! Simply and easily. 
// server end code 
namespace domain { 
struct Foo { 
void do_foo() { cout << "Foo usedn"; } 
}; 
struct Bar { 
void do_bar() { cout << "Bar usedn"; } 
}; 
struct Baz { 
void do_baz() { cout << "Baz usedn"; } 
}; 
struct FooBarBaz { 
Foo f_; 
Bar b_; 
Baz z_; 
void do_foobarbaz { 
f.do_foo(); 
b.do_bar(); 
z.do_baz(); 
} 
}; 
} 
// client end code 
void call() { 
domain::FooBarBaz fbz; 
fbz.do_foobarbaz (); 
} 
4:54:14 AM 
85
The facade 
• What’s that? The façade pattern! 
• GoF: “Provide a unified interface to a set of interfaces in a 
subsystem. Facade defines a higher-level interface that makes the 
subsystem easier to use” 
• This is typical design method of package level interface. On the view 
of client end, the package it used is much like another objects while 
delegate all messages to its internal constructs. 
• Client end should always depend on the package interface instead of 
its internal implementation. If fine granularity controlling is needed, 
just export those necessary, wrapped subsystem interfaces. 
4:54:14 AM 
86
The mediator (TODO) 
• What’s that? The mediator pattern! 
• GoF: “Define an object that encapsulates how a set of objects 
interact. Mediator promotes loose coupling by keeping objects 
from referring to each other explicitly, and it lets you vary 
their interaction independently” 
4:54:14 AM 
87
The iterator (TODO) 
• What’s that? The iterator pattern! 
• GoF: “Provide a way to access the elements of an aggregate 
object sequentially without exposing its underlying 
representation” 
4:54:14 AM 
88
The rest GoF patterns 
4:54:14 AM 
89
Shared fine-grained object 
4:54:14 AM 
90
The flyweight (TODO) 
• GoF: “Use sharing to support large numbers of fine-grained 
objects efficiently” 
4:54:14 AM 
91
The interpreter (TODO) 
• GoF: “Given a language, define a represention for its grammar 
along with an interpreter that uses the representation to 
interpret sentences in the language” 
4:54:14 AM 
92

More Related Content

What's hot

Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010
Satish Verma
 

What's hot (19)

Mixing Source and Bytecode: A Case for Compilation By Normalization (OOPSLA 2...
Mixing Source and Bytecode: A Case for Compilation By Normalization (OOPSLA 2...Mixing Source and Bytecode: A Case for Compilation By Normalization (OOPSLA 2...
Mixing Source and Bytecode: A Case for Compilation By Normalization (OOPSLA 2...
 
A peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk UserA peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk User
 
Introduction to Kotlin for Java developer
Introduction to Kotlin for Java developerIntroduction to Kotlin for Java developer
Introduction to Kotlin for Java developer
 
EKON 25 Python4Delphi_mX4
EKON 25 Python4Delphi_mX4EKON 25 Python4Delphi_mX4
EKON 25 Python4Delphi_mX4
 
Contract First Development with Microsoft Code Contracts and Microsoft Pex at...
Contract First Development with Microsoft Code Contracts and Microsoft Pex at...Contract First Development with Microsoft Code Contracts and Microsoft Pex at...
Contract First Development with Microsoft Code Contracts and Microsoft Pex at...
 
Latest C++ Interview Questions and Answers
Latest C++ Interview Questions and AnswersLatest C++ Interview Questions and Answers
Latest C++ Interview Questions and Answers
 
Eval4j @ JVMLS 2014
Eval4j @ JVMLS 2014Eval4j @ JVMLS 2014
Eval4j @ JVMLS 2014
 
Manage software dependencies with ioc and aop
Manage software dependencies with ioc and aopManage software dependencies with ioc and aop
Manage software dependencies with ioc and aop
 
Ekon 25 Python4Delphi_MX475
Ekon 25 Python4Delphi_MX475Ekon 25 Python4Delphi_MX475
Ekon 25 Python4Delphi_MX475
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Sour Pickles
Sour PicklesSour Pickles
Sour Pickles
 
The why and how of moving to php 7
The why and how of moving to php 7The why and how of moving to php 7
The why and how of moving to php 7
 
Assign
AssignAssign
Assign
 
Protocol Buffer.ppt
Protocol Buffer.pptProtocol Buffer.ppt
Protocol Buffer.ppt
 
Andy On Closures
Andy On ClosuresAndy On Closures
Andy On Closures
 
Programming with Python - Basic
Programming with Python - BasicProgramming with Python - Basic
Programming with Python - Basic
 
Lego for Software Engineers at Silicon Valley Code Camp 2011 (2010-10-10)
Lego for Software Engineers at Silicon Valley Code Camp 2011 (2010-10-10)Lego for Software Engineers at Silicon Valley Code Camp 2011 (2010-10-10)
Lego for Software Engineers at Silicon Valley Code Camp 2011 (2010-10-10)
 
Visual Studio .NET2010
Visual Studio .NET2010Visual Studio .NET2010
Visual Studio .NET2010
 
Vladimir Ulogov - Beyond the Loadable Module
Vladimir Ulogov - Beyond the Loadable ModuleVladimir Ulogov - Beyond the Loadable Module
Vladimir Ulogov - Beyond the Loadable Module
 

Viewers also liked

Design patterns intro
Design patterns introDesign patterns intro
Design patterns intro
Jean Pаoli
 
The 23 gof design patterns in java ,the summary
The 23 gof design patterns in java ,the summaryThe 23 gof design patterns in java ,the summary
The 23 gof design patterns in java ,the summary
achraf_ing
 
eXtreme programming
eXtreme programmingeXtreme programming
eXtreme programming
Jean Pаoli
 

Viewers also liked (20)

Patterns go f
Patterns go fPatterns go f
Patterns go f
 
Infostroy 2013
Infostroy 2013Infostroy 2013
Infostroy 2013
 
Modern software development anti patterns (OSCON 2012)
Modern software development anti patterns (OSCON 2012)Modern software development anti patterns (OSCON 2012)
Modern software development anti patterns (OSCON 2012)
 
Go f designpatterns 130116024923-phpapp02
Go f designpatterns 130116024923-phpapp02Go f designpatterns 130116024923-phpapp02
Go f designpatterns 130116024923-phpapp02
 
Design Patterns - GOF
Design Patterns - GOFDesign Patterns - GOF
Design Patterns - GOF
 
Design patterns intro
Design patterns introDesign patterns intro
Design patterns intro
 
The Big Red Book - Panavision
The Big Red Book - PanavisionThe Big Red Book - Panavision
The Big Red Book - Panavision
 
Java8 - Interfaces, evolved
Java8 - Interfaces, evolvedJava8 - Interfaces, evolved
Java8 - Interfaces, evolved
 
Design patterns illustrated-2015-03
Design patterns illustrated-2015-03Design patterns illustrated-2015-03
Design patterns illustrated-2015-03
 
The 23 gof design patterns in java ,the summary
The 23 gof design patterns in java ,the summaryThe 23 gof design patterns in java ,the summary
The 23 gof design patterns in java ,the summary
 
Java - Singleton Pattern
Java - Singleton PatternJava - Singleton Pattern
Java - Singleton Pattern
 
eXtreme programming
eXtreme programmingeXtreme programming
eXtreme programming
 
Design Anti Patterns - How to Design a Poor Web Experience
Design Anti Patterns - How to Design a Poor Web ExperienceDesign Anti Patterns - How to Design a Poor Web Experience
Design Anti Patterns - How to Design a Poor Web Experience
 
Domain logic patterns of Software Architecture
Domain logic patterns of Software ArchitectureDomain logic patterns of Software Architecture
Domain logic patterns of Software Architecture
 
Anti Patterns
Anti PatternsAnti Patterns
Anti Patterns
 
Design pattern with Java 8
Design pattern with Java 8Design pattern with Java 8
Design pattern with Java 8
 
Out of box page object design pattern, java
Out of box page object design pattern, javaOut of box page object design pattern, java
Out of box page object design pattern, java
 
Design Patterns Presentation - Chetan Gole
Design Patterns Presentation -  Chetan GoleDesign Patterns Presentation -  Chetan Gole
Design Patterns Presentation - Chetan Gole
 
Gof design patterns
Gof design patternsGof design patterns
Gof design patterns
 
Design patterns
Design patternsDesign patterns
Design patterns
 

Similar to From code to pattern, part one

iOS 2 - The practical Stuff
iOS 2 - The practical StuffiOS 2 - The practical Stuff
iOS 2 - The practical Stuff
Petr Dvorak
 
Vorontsov, golovko ssrf attacks and sockets. smorgasbord of vulnerabilities
Vorontsov, golovko   ssrf attacks and sockets. smorgasbord of vulnerabilitiesVorontsov, golovko   ssrf attacks and sockets. smorgasbord of vulnerabilities
Vorontsov, golovko ssrf attacks and sockets. smorgasbord of vulnerabilities
DefconRussia
 
Java cçccfftshrssfuutrfuuggiuffus201-java.ppt
Java cçccfftshrssfuutrfuuggiuffus201-java.pptJava cçccfftshrssfuutrfuuggiuffus201-java.ppt
Java cçccfftshrssfuutrfuuggiuffus201-java.ppt
scsankalp03
 
JavaAdvanced programming for expertes dsd
JavaAdvanced programming for expertes dsdJavaAdvanced programming for expertes dsd
JavaAdvanced programming for expertes dsd
meharikiros2
 
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
goccy
 

Similar to From code to pattern, part one (20)

CDI In Real Life
CDI In Real LifeCDI In Real Life
CDI In Real Life
 
iOS 2 - The practical Stuff
iOS 2 - The practical StuffiOS 2 - The practical Stuff
iOS 2 - The practical Stuff
 
Vorontsov, golovko ssrf attacks and sockets. smorgasbord of vulnerabilities
Vorontsov, golovko   ssrf attacks and sockets. smorgasbord of vulnerabilitiesVorontsov, golovko   ssrf attacks and sockets. smorgasbord of vulnerabilities
Vorontsov, golovko ssrf attacks and sockets. smorgasbord of vulnerabilities
 
Php extensions
Php extensionsPhp extensions
Php extensions
 
Plone 5.2 migration at University Ghent, Belgium
Plone 5.2 migration at University Ghent, BelgiumPlone 5.2 migration at University Ghent, Belgium
Plone 5.2 migration at University Ghent, Belgium
 
UNIT-IV WT web technology for 1st year cs
UNIT-IV WT web technology for 1st year csUNIT-IV WT web technology for 1st year cs
UNIT-IV WT web technology for 1st year cs
 
PHP 8: Process & Fixing Insanity
PHP 8: Process & Fixing InsanityPHP 8: Process & Fixing Insanity
PHP 8: Process & Fixing Insanity
 
Java cçccfftshrssfuutrfuuggiuffus201-java.ppt
Java cçccfftshrssfuutrfuuggiuffus201-java.pptJava cçccfftshrssfuutrfuuggiuffus201-java.ppt
Java cçccfftshrssfuutrfuuggiuffus201-java.ppt
 
DSL's with Groovy
DSL's with GroovyDSL's with Groovy
DSL's with Groovy
 
Polymorphism Using C++
Polymorphism Using C++Polymorphism Using C++
Polymorphism Using C++
 
Pharo foreign function interface (FFI) by example by Esteban Lorenzano
Pharo foreign function interface (FFI) by example by Esteban LorenzanoPharo foreign function interface (FFI) by example by Esteban Lorenzano
Pharo foreign function interface (FFI) by example by Esteban Lorenzano
 
gRPC: Beyond REST
gRPC: Beyond RESTgRPC: Beyond REST
gRPC: Beyond REST
 
Dojo for programmers (TXJS 2010)
Dojo for programmers (TXJS 2010)Dojo for programmers (TXJS 2010)
Dojo for programmers (TXJS 2010)
 
JavaAdvanced programming for expertes dsd
JavaAdvanced programming for expertes dsdJavaAdvanced programming for expertes dsd
JavaAdvanced programming for expertes dsd
 
Perl5 meta programming
Perl5 meta programmingPerl5 meta programming
Perl5 meta programming
 
Getting Started with Go
Getting Started with GoGetting Started with Go
Getting Started with Go
 
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)これからのPerlプロダクトのかたち(YAPC::Asia 2013)
これからのPerlプロダクトのかたち(YAPC::Asia 2013)
 
Finding Needles in Haystacks
Finding Needles in HaystacksFinding Needles in Haystacks
Finding Needles in Haystacks
 
Modern PHP
Modern PHPModern PHP
Modern PHP
 
Improving the Pharo VM
Improving the Pharo VMImproving the Pharo VM
Improving the Pharo VM
 

Recently uploaded

Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
Neometrix_Engineering_Pvt_Ltd
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
Epec Engineered Technologies
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
MsecMca
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
dharasingh5698
 

Recently uploaded (20)

FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
VIP Model Call Girls Kothrud ( Pune ) Call ON 8005736733 Starting From 5K to ...
 
Thermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.pptThermal Engineering -unit - III & IV.ppt
Thermal Engineering -unit - III & IV.ppt
 
Employee leave management system project.
Employee leave management system project.Employee leave management system project.
Employee leave management system project.
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
(INDIRA) Call Girl Meerut Call Now 8617697112 Meerut Escorts 24x7
 
Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Netaji Nagar, Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
 
Design For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the startDesign For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the start
 
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdfONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
ONLINE FOOD ORDER SYSTEM PROJECT REPORT.pdf
 
22-prompt engineering noted slide shown.pdf
22-prompt engineering noted slide shown.pdf22-prompt engineering noted slide shown.pdf
22-prompt engineering noted slide shown.pdf
 
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Wakad Call Me 7737669865 Budget Friendly No Advance Booking
 
KubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghlyKubeKraft presentation @CloudNativeHooghly
KubeKraft presentation @CloudNativeHooghly
 
Integrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - NeometrixIntegrated Test Rig For HTFE-25 - Neometrix
Integrated Test Rig For HTFE-25 - Neometrix
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
 
data_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdfdata_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdf
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
 

From code to pattern, part one

  • 1. From Code to Pattern Understanding classical GoF patterns with C++
  • 2. Agenda • Why this necessary • OO fundamental • OO in C++ • GoF classical pattern • Creational • Structural and behavioral • Inter-operational 4:54:14 AM 2
  • 3. Why this necessary • Know what those terms mean on earth • Know how they work • Know why they came • Know how to connect to your daily work 4:54:14 AM 3
  • 4. OO concepts Class 4:54:14 AM 4
  • 5. OOD principles • Program to an interface, not an implementation • Favor object composition over class inheritance • SOLID • Single responsibility principle • A class exist only for one reason • Open/closed principle • Add a new feature through extend exist class instead of modify it • Liskov substitution principle • In all cases, subclass can substitute its parent without invalidate any desirable state • Interface segregation principle • Prefer specific interfaces than general purpose interface • Dependency inversion principle • Depends on abstract instead of high-level or low-level module 4:54:14 AM 5
  • 6. How OOD works • Finding Appropriate Objects • Find the nouns in user case/scenario • Determining Object Granularity • Refine the noun if it can do complete unrelated things • Specifying Object Interfaces • Define what the object can do • Specifying Object Implementations • Define how the object does 4:54:14 AM 6
  • 7. The core of OO • Type and class • Interface is the message it can handle • Type is interface set • Class is type implementation • A class may have(support) more types • Messaging • The sender • The receiver • The message • The message body • Inheritance relationship • “is-a”? • “has-a”? • “implement-a”? • Abstraction • Bind data and behaviors together • Hide as more as possible information 4:54:14 AM 7
  • 8. The core of OO in C++ • Type and class • Interface is the message it can handle Virtual function in abstract class • Type is interface set Abstract class • Class is type implementation Concrete class • A class may have(support) more types Multiple inheritance class • Messaging • The sender None or implicit object • The receiver Named object • The message Named member method • The message body Parameters of member function • Inheritance relationship • “is-a”? Public inheritance from class • “has-a”? Private inheritance or object composition • “implement-a”? Public inheritance from type • Abstraction • Bind data and behaviors together Member variables and methods • Hide as more as possible information Access modifier 4:54:14 AM 8
  • 9. The simplest case study • Set-and-call style // client end code void call() { Foo foo; foo.set_property("id", 100); foo.set_property("name", "wooooo"); foo.bar(); } • Try to identify the hardcode points • Some questions • How does an object get to create? • How does an object get to destroy? • How to send a message to an object? • How does the object handle a message? 4:54:14 AM 9
  • 10. How can it be flexible? • Avoid hardcode! But what’s hardcode then? • Data hardcode • Hardcoded path, name, value etc. • Should be avoided always and easy to do • Structure hardcode • Fixed class implementation • Derivation relationship • Use a class name directly • Use a method name directly • Add an extra layer • Structure layer • Interactive layer • We get flexibility with the cost of complexity! • Be sensitive with tradeoff 4:54:14 AM 10
  • 11. Design pattern, the definition • Wikipedia: “… is general reusable solution to a commonly occurring problem in software design” • GoF: “… names, abstracts, and identifies the key aspects of a common design structure that make it useful for creating a reusable object-oriented design” • Essential of DP • Specific name • Scenario • Solution • We are going to: • Show how simple codes are evolved and refactored to meet more requirements and • Show how GoF classify and name it • NOTE • The sample code does not care the delete of object. Just as object creation, there are patterns to handle object lifecycle, such as RAII. 4:54:14 AM 11
  • 13. How to get an object? I • You know the class name • Fully type information available only at compile-time • Stack based object • Pros • Straight • Easy to use • Map to language structure directly • Cons • Compile-time limitation • Scope based Lifecycle • Hardcoded type • Strict couple of server end code and client end code // server end code struct Foo { void bar() { cout << “bar calledn"; } }; struct Foo2 { void bar() { cout << “bar2 calledn"; } }; void bang(Foo* foo, Foo2* foo2) { foo->bar(); foo2->bar(); } // client end code void call() { Foo foo; Foo2 foo2 bang(&foo, &foo2); } 4:54:14 AM 13
  • 14. How to get an object? II • Heap based object • Pros • Long life across scope • Easy to use still • Map to language structure directly • Cons • Hardcoded type name • Still tightly coupling // server end code struct Foo { void bar() { cout << "bar calledn"; } }; struct Foo2 { void bar() { cout << "bar2 calledn"; } }; void bang(Foo* foo, Foo2* foo2) { foo->bar(); foo2->bar(); } // client end code Foo* get_foo() { return new Foo; } Foo2* get_foo2() { return new Foo2; } void call() { Foo* foo = get_foo(); Foo2* foo2 = get_foo2(); bang(foo, foo2); } 4:54:14 AM 14
  • 15. How to get an object? III • First try of refactor • Abstract the interface • Server end code cares about the interface that Foo exposes instead of Foo object • Pros • Decouple server end code so that it’ll not depends on the Foo definition • Cons • New derivation layer • For any new implementation of IFoo interface, client end code must be modified // server end code struct IFoo { virtual void bar() = 0; }; void bang(const vector<IFoo*> vf) { for_each(vf.begin(), vf.end(), mem_fun(&IFoo::bar)); } // client end code struct Foo : IFoo { virtual void bar() { cout << "bar calledn"; } }; struct Foo2 : IFoo { virtual void bar() { cout << "bar2 calledn"; } }; IFoo* get_foo() { return new Foo; } IFoo* get_foo2() { return new Foo2; } void call() { vector<IFoo*> vf; vf.push_back(get_foo()); vf.push_back(get_foo2()); bang(vf); } 4:54:14 AM 15
  • 16. How to get an object? IV • Second try of refactor • Abstract the creation of object • Decouple server end code and client code completely • Pros • Easy to add new IFoo interface implementation without change server end and client end code • Server end code only define the interfaces and the business logics skeleton • Cons • Complex with double derivation layers // server end code struct IFoo { virtual void bar() = 0; }; struct IFooCreater { virtual IFoo* create() = 0; }; void bang(IFooCreater* fc) { fc->create() ->bar(); } struct Foo : IFoo { virtual void bar() { cout << "bar calledn"; } }; struct Foo2 : IFoo { virtual void bar() { cout << "bar2 calledn"; } }; struct FooCreater : IFooCreater { enum FooType {TFoo, TFoo2} type_; FooCreater(FooType t) : type_(t) {} virtual IFoo* create() { if (type_ == TFoo) return new Foo; if (type_ == TFoo2) return new Foo2; assert(0); return 0; } }; void call() { bang(new FooCreater(FooCreater::TFoo)); bang(new FooCreater(FooCreater::TFoo2)); } 4:54:14 AM 16
  • 17. The Factory Method • What’s that? The Factory method! • GoF: “Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses” 4:54:14 AM 17
  • 18. How to get an object? I • You have no class name, but an existed object • Copy constructor? • Need to know the class of the object • RTTI? • Not fully typed information • There is no built-in support in C++! • The first try • Seems useless at all, I know it’s Foo here! • An incorrect user scenario // server end code class Foo { public: Foo* clone() { return new Foo(*this); } }; vector<Foo*> foos; void bang(Foo* f) { Foo* baby = f->clone(); // change some attributes foos.push_back(baby); } // client end code static Foo default_foo; void call() { bang(&default_foo); } 4:54:14 AM 18
  • 19. How to get an object? II • The second try • Server end code should not care about the class of the object • Pros • Again, we move the concrete implementation to client end • Again, we can easily add new // server end code struct IFoo { virtual void bar() = 0; virtual IFoo* clone() = 0; }; vector<IFoo*> foos; void bang(IFoo* f) { IFoo* baby = f->clone(); // change some attributes foos.push_back(baby); } // client end code class Foo : public IFoo { virtual Foo* clone() { return new Foo(*this); } virtual void bar() {} }; static Foo default_foo; void call() { bang(&default_foo); } 4:54:14 AM 19
  • 20. The Prototype • What’s that? The prototype! • GoF: “Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype” • Dynamic languages don’t need this pattern as all type information are available on runtime 4:54:14 AM 20
  • 21. How to get the object? I • In prototype sample, there is a default instance and all other copies are cloned from it. • And the instance should be global unique • Should not be constructed by user • Should be ready before the first use • Should be cleanup elegance • Had better never be constructed if it’s not be used • So 1. Private constructor 2. Runtime library constructed instance (conflict with 1) or runtime construct with condition 3. Resource management 4. Lazy-initialized 4:54:14 AM 21
  • 22. How to get the object? II • The initial implementation • some issues • IFoo implementation is bond to server end and not easy to extend • Mixed functionalities of class FooSingleton: it implements both IFoo and singleton interface // server end code struct IFoo { virtual void bar() = 0; }; struct FooSingleton : public IFoo { static IFoo* get_instance() { if (!instance_) instance_ = new FooSingleton; return instance_; } void bar() { cout << "bar calledn"; } private: FooSingleton() {} static IFoo* instance_; }; IFoo* FooSingleton::instance_ = 0; // client end code void call() { IFoo* foo = FooSingleton::get_instance(); foo->bar(); } 4:54:14 AM 22
  • 23. How to get the object? III • The final try • Use another pattern we have not discussed (the bridge pattern) to avoid the cohesion between interface and implementation // server end code struct IFoo { virtual void bar() = 0; }; struct IFooImpl { virtual void bar_impl() = 0; }; struct FooSingleton : public IFoo { static IFoo* get_instance(IFooImpl* impl) { if (!instance_) instance_ = new FooSingleton(impl); return instance_; } void bar() { impl_->bar_impl(); } private: FooSingleton(IFooImpl* i) : impl_(i) {} IFooImpl* impl_; static IFoo* instance_; }; IFoo* FooSingleton::instance_ = 0; // client end code struct MyImpl : IFooImpl { void bar_impl() { cout << "bar calledn"; } }; void call() { IFoo* foo = FooSingleton::get_instance(new MyImpl); foo->bar(); } 4:54:14 AM 23
  • 24. The Singleton • What’s that? The singleton pattern! • GoF: “Ensure a class only has one instance, and provide a global point of access to it” • More discussion on singleton • Thread safety consideration • Dependency among singletons • Double-check idioms • Return reference instead of pointer 4:54:14 AM 24
  • 25. How to get some objects? I • OK, we need some related or dependent objects • Same class? • Stack based object array or heap based dynamic object. Works only if the Foo has a default constructor. // client end code void same_class() { Foo foos1[100]; Foo* foos2 = new Foo[100]; vector<Foo> foos3(100); // cannot return foos1 // had better avoid return foos3 } 4:54:14 AM 25 // // server end code, none
  • 26. How to get some objects? II • Different class but same type? • Construct directly • Or use some factories // server end code strcut IFoo { virtual void bar() = 0; }; struct D1 : IFoo { virtual void bar() {...} }; struct D2 : IFoo { virtual void bar() {...} }; void bang(const vector<IFoo*>& fs) { for_each(fs.begin(), fs.end(), mem_fun(&IFoo::bar)); } // client end code void call() { vector<IFoo*> fs; fs.push_back(new D1); fs.push_back(new D2); bang(fs); } 4:54:14 AM 26
  • 27. How to get some objects? III • Different type? • Cannot get a list of object that have no shared type • Instead, use a struct to warp them and make each object as a member and use them by name • Then, can you more specific? • Say, type1 and type2 can be subtyped both dynamically … struct package { type1 v1; type2 v2; // … }; void diff_type() { package p; // use(get/set) each member // can return if necessary } 4:54:14 AM 27 // // server end code, none
  • 28. How to get some objects? IV • Let’s have a try • Reconsider the scenario, we are building a C language compiler front end skeleton, and it includes preprocessor and assembler. • How can we support another language, say C++, while will not affect the server end code? // server end code struct front_end { preprocesser* pp_; assembler* as_; void compile(string file) { as_->doit(pp_->doit(file)); } }; void do_compile(string file) { front_end* fe = new front_end; fe->pp_ = new preprocesser; fe->as_ = new assembler; fe->compile(file) } // client end code void call() { do_compile("hello.c"); } 4:54:14 AM 28
  • 29. How to get some objects? V • Refactor it so that it can easy support more language • Abstract interface of preprocess and assemble, push the implementation to client end. // server end code struct IPreprocesser { virtual string doit(string f) = 0; }; struct IAssemble { virtual string doit(string f) = 0; }; struct IFront_end_creator { virtual IPreprocesser* create_pp() = 0; virtual IAssemble* create_as() = 0; }; class front_end { IPreprocesser* pp_; IAssemble* as_; public: front_end(IFront_end_creator* c) { pp_ = c->create_pp(); as_ = c->create_as(); } void compile(string file) { as_->doit(pp_->doit(file)); } }; 4:54:14 AM 29
  • 30. How to get some objects? VI • The client code for C (right) • The client code for C++ (below) // client end code: C front end struct CPreprocess : IPreprocesser { virtual string doit(string f) { return f; } }; struct CAssembale : IAssemble { virtual string doit(string f) { return f; } }; struct Cfe : IFront_end_creator { virtual IPreprocesser* create_pp(){ return new CPreprocess; } virtual IAssemble* create_as() { return new CAssembale; } }; // Client end code: C++ front end struct CPPPreprocess : IPreprocesser { virtual string doit(string f) { return f; } }; struct CPPAssembale : IAssemble { virtual string doit(string f) { return f; } }; struct CPPfe : IFront_end_creator { virtual IPreprocesser* create_pp() { return new CPPPreprocess; } virtual IAssemble* create_as() { return new CPPAssembale; } }; // client end code, how to use void call() { front_end cfe(new Cfe); fe.compile("hello.c"); front_end cppfe(new CPPfe); fe.compile("hello.cpp"); } 4:54:14 AM 30
  • 31. The Abstract Factory • A little complex, let’s summary what we did by now • A derivation layer that create some related objects (IFront_end_creater) • An object that depends on the creator to create objects of another derivation layers (IPreprocesser and IAssemble) • What’s this? The Abstract Factory! • GoF: “Provide an interface for creating families of related or dependent objects without specifying their concrete classes” 4:54:14 AM 31
  • 32. How get an object from data? I • Do you mean object serialization and deserialization? • Almost, but how? • so we have ... • Note, not clear boundary between server and client. • This is the simplest case and cannot fit complex scenarios such as the member is a point to some type • C++ has no reflect mechanism so that we save type information to file directly and then we can construct an object from it directly • Overriding works only if the concrete object is ready, but we have no yet. Chicken or eggs, eh? struct record { int id_; string name_; void serialize(ostream& os) { os << id_; os << name_ << endl; } void deserialize(istream& is) { is >> id_; is >> name_; } }; void call() { record r; ifstream ifs("/root/data"); r.deserialize(ifs); } 4:54:14 AM 32
  • 33. How get an object from data? II • Assume we are going to serialize front_end object and we only check the process of deserializing. • In order to get the class of concrete object, we must save the information as well as object data. So • each class derived from serializer should have a static global unique ID • we should serialize the ID before the object data • The next question is: where does the relationship between ID and class exist? • we need another helper type! // server end code struct serializer { virtual void save(ostream& os) = 0; virtual void load(istream& is) = 0; }; struct IPreprocesser : serializer { virtual string doit(string f) = 0; }; struct IAssemble : serializer { virtual string doit(string f) = 0; }; class front_end : serializer { IPreprocesser* pp_; IAssemble* as_; public: virtual void save(ostream& os) { pp_.save(os); as_.save(os); } virtual void load(istream& is) { // ?? } }; 4:54:14 AM 33
  • 34. How get an object from data? III • The help class will help construct correct concrete object according the object ID. • Server end code first get the object via helper and than load it // server end code struct front_end : serializer { IPreprosseser* pp_; IAssemble* as_; ILoader* loader_; virtual void save(ostream& os) { os << pp_->id() << endl; pp_->save(os); os << as_->id() << endl; as_->save(os); } virtual void load(istream& is) { string pp_id, as_id; is >> pp_id; pp_ = loader_->get_pp(pp_id); pp_->load(is); is >> as_id; as_ = loader_->get_as(as_id); as_->load(is); } }; // server end code struct serializer { virtual string id() const = 0; virtual void save(ostream&) = 0; virtual void load(istream&) = 0; }; struct IPreprosseser : serializer {}; struct IAssemble : serializer {}; struct ILoader { virtual IPreprosseser* get_pp(string) = 0; virtual IAssemble* get_as(string) = 0; }; 4:54:14 AM 34
  • 35. How get an object from data? IV • Client end provides the implementation of the helper class and specify different ID for different class. struct Front_end_loader : ILoader { virtual IPreprosseser* get_pp(string id) { if (id == CPreprocess::uuid) return new CPreprocess; else if (id == CPPPreprocess::uuid) return new CPPPreprocess; else throw "invalid preprocesser class id"; } virtual IAssemble* get_as(string id) { if (id == CAssemble::uuid) return new CAssemble; else if (id == CPPAssemble::uuid) return new CPPAssemble; else throw "invalid assemble class id"; } }; // C front end implementation code struct CPreprocess : IPreprocesser { static string uuid; virtual string id() const { return uuid; } virtual void save(ostream& os) const {} virtual void load(istream& is) {} }; string CPreprocess::uuid = "CPreprocess"; struct CAssemble : IAssemble { static string uuid; virtual string id() const { return uuid; } virtual void save(ostream& os) const {} virtual void load(istream& is) {} }; string CAssemble::uuid = "CAssemble"; void call() { const char* file = "C:test.dat"; Front_end_loader loader; front_end fe(&loader); bk.load(ifstream(file)); } 4:54:14 AM 35
  • 36. The Builder • We get running codes which satisfy following requirements • Type based serialization/deserialization • Easy to add new subtype without need modify the server end code • Focus on the part of loading. What’s that? The Builder Pattern! • GoF: “Separate the construction of a complex object from its representation so that the same construction process can create different representations” 4:54:14 AM 36
  • 37. Sidebar: resource management • We ignore the issue of resource management at all in previous discussion • There is no default GC support in C++, but we have an elegant alternative, that’s RAII based resource management policy • Put it simple, use std::shared_ptr or std::unique_ptr always for all places that need a raw pointer • For other non-pointer resource, such as kernel object handle, locker, database connection, network connection etc., use RAII plus reference counted wrapper if need. • This is a big and serious topic and we need talk it separately. 4:54:14 AM 37
  • 38. Sending a message 4:54:14 AM 38
  • 39. The object and its behaviors • Object • Object type. The message set the object accepts. • Object class. The implementation of object types plus data that represent object status. • Object Id. The unique identifier of any object. • For C++ language level object, it’s memory address of the object • That is why objects of zero size class have different address • Object behavior: how the object handle a message • Object status decide the behaviors of it • Those behaviors that do not depend on status are static behaviors and will not be discussed here • How to change an object? • Set object status directly • Call a r/w behavior of object 4:54:14 AM 39
  • 40. Send a message to object • Review C++ syntax of sending a message • Null or implicit caller • Directly depends on the detailed concrete object or a pointer to a type • Hardcoded message name, the member function name • Hardcoded massage property, the argument of the operation • The message is taken action at once • In C++, the sender is null (in global function, class static member function) or implicitly (in class member function). • Depends on the type implementation, C++ runtime will route the message to correct concrete object. • That’s polymorphism. • C++ runtime only cares about the target object • What if you want to routine the message by not only the type of target but the type of source? • That’s called double dispatch • Switch/case? Be a respectful programmer and forget it! 4:54:14 AM 40
  • 41. Double dispatch I • Target uses C++ override mechanism to distinguish different source class and transfer the message back to source, the first dispatch. • Source uses C++ overload mechanism to distinguish different target class, the second dispatch. • We have follow initial implementation // server end code struct Source; struct Target { virtual void m(Source*) = 0; }; struct T1 : Target {virtual void m(Source* s); }; struct T2 : Target { virtual void m(Source* s); }; struct Source { virtual void m(T1*) = 0; virtual void m(T2*) = 0; }; struct S1 : Source { virtual void m(T1* t) { cout << "S1->T1n"; } virtual void m(T2* t) { cout << "S1->T2n"; } }; struct S2 : Source { virtual void m(T1* t) { cout << "S2->T1n"; } virtual void m(T2* t) { cout << "S2->T2n"; } }; void T1::m(Source* s) { s->m(this); } void T2::m(Source* s) { s->m(this); } // client end code void call() { Source* s1 = new S1; Source* s2 = new S2; Target* t1 = new T1; Target* t2 = new T2; t1->m(s1); t1->m(s2); t2->m(s1); t2->m(s2); } 4:54:14 AM 41
  • 42. Double dispatch II • Message m for target is only for exposing itself so that source can do more. That is, it accepts that object and transfer the control back to the object, so we rename the message as “accept” • Message m for source is the actually place we can handle different target type. It provides all possible target type overloads and visit them respectively, so we rename the message as “visit” • Meanwhile, the type source provides all possible overloads of derived class of type Target. That means it can walk the class hierarchy of type Target. So we rename is as “Visitor” • Finally, we get following codes. • What is it? • It provides the possible that add new operation to an existed class hierarchy. • The Visitor class is strong bound to Target class and any change of the Target class hierarchy will cause the change of Visitor interface. // server end code struct Visitor; struct Target { virtual void accept(Visitor*) = 0; }; struct T1 : Target { virtual void accept(Visitor* s); }; struct T2 : Target { virtual void accept(Visitor* s); }; struct Visitor{ virtual void visit(T1*) = 0; virtual void visit(T2*) = 0; }; void T1::accept(Visitor* s) { s->visit(this); } void T2::accept(Visitor* s) { s->visit(this); } 4:54:14 AM 42
  • 43. The Visitor • What’s this? It’s Visitor pattern! • GoF: “Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.” 4:54:14 AM 43
  • 44. Send a message to an object • Review C++ syntax of sending a message • Null or implicit caller • Directly depends on the detailed concrete object or a pointer to a type • Hardcoded message name, the member function name • Hardcoded massage property, the argument of the operation • The message is taken action at once • How can it possible to erase those? 4:54:14 AM 44 //serve end code struct Target { void foo() { cout << "Target::foo calledn"; } }; // client end code void call() { Target t; t.foo(); }
  • 45. Indirect messaging I • Use an indirect layer to wrapper the message target • Binding the message name to the wrapped message target //serve end code struct Target; struct Wrapper { typedef void (Target::*Action)(); Target* t_; Action a_; Wrapper(Target* t, Action a) : t_(t), a_(a) {} void call() const { (t_->*a_)(); } }; struct Target { void foo() { cout << "Target::foo calledn"; } }; // client end code void call() { Target t; Wrapper w(&t, &Target::foo); w.call(); } 4:54:14 AM 45
  • 46. Indirect messaging II • Try to refactor it • Programming for interface • Const correctness • Use template to support multiple concrete classes // serve end code struct IWrapper { virtual void call() const= 0; }; template <typename T> struct Wrapper : IWrapper { typedef void (T::*Action)(); T* t_; Action a_; Wrapper(T* t, Action a) : t_(t), a_(a) {} virtual void call() const { (t_->*a_)(); } }; // client end code struct Target{ void foo() { cout << "Target::foo calledn"; } } t; struct Another { void bar() { cout << "Another::foo calledn"; } } a; void call() { vector<IWrapper*> vw; vw.push_back( new Wrapper<Target>(&t, &Target::foo)); vw.push_back( new Wrapper<Target>(&a, &Another::foo)); for_each(vw.begin(), vw.end(), mem_fun(&IWrapper::call)); } 4:54:14 AM 46
  • 47. The Command • What do we get? The Command pattern! • GoF: “Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations” • Question • How to support undo with this pattern? 4:54:14 AM 47
  • 48. Broadcast a message • With native C++ support, we can only send one message to one object once. • How can we send a message to some objects? • Loop on the object array/list/tree? 4:54:14 AM 48
  • 49. Message broadcasting I • In order to broadcast a message, we need • The message to be broadcasted • The target objects and they must can handle the message • An very native implementation //serve end code struct Target1 { void foo() const { } }; struct Target2 { void foo() const { } }; struct Broadcaster { Target1 t1_; Target1 t2_; void broadcast() { t1_.foo(); t2_.foo(); } }; // client end code void call() { Broadcaster b; b.broadcast(); } 4:54:14 AM 49
  • 50. Message broadcasting II • Refactor actions • Abstract the unique interface • Push code to client • Dynamic target objects //serve end code struct ITarget { virtual void foo() const = 0; }; struct Broadcaster { vector<ITarget*> ts_; void broadcast() { for_each(ts_.begin(), ts_.end(), mem_fun(&ITarget::foo)); } void AddTarget(ITarget* t) { ts_.push_back(t); } }; // client end code struct Target1 : ITarget { virtual void foo() const { } }; struct Target2 : ITarget { virtual void foo() const { } }; void call() { Broadcaster b; b.AddTarget(new Target1); b.AddTarget(new Target2); b.broadcast(); } 4:54:14 AM 50
  • 51. Message broadcasting III • It’s possible that the broadcaster itself will broadcast something if its state changes • Provides subscribe & unsubscribe interface • Callback to all subscribers if something occurs //serve end code struct ITarget { virtual void foo() const = 0; }; struct Broadcaster { vector<ITarget*> ts_; void broadcast() { for_each(ts_.begin(), ts_.end(), mem_fun(&ITarget::foo)); } void subscribe(ITarget* t) { ts_.push_back(t); } void unsubscribe(ITarget* t) { ts_.remove(t); } }; 4:54:14 AM 51
  • 52. The Observer • What’s that? The Observer pattern! • GoF: “Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically” 4:54:14 AM 52
  • 53. Send a message to someone • OO always requires specific target, sometimes it’s rigorous • The target is unknown on sending time (distributed environment) • The sender does not care who will handle it • There are maybe some policies to control what target will handle the message (load balance) • The target objects may have different priority to handle such message • How can it possible? • All problems in computer science can be solved by another level of indirection. So we need a gateway to get the message at first. • Meanwhile, we also need routine the message to other if itself cannot handle it, so we need chains them together 4:54:14 AM 53
  • 54. Uncertain handler I • First try • Use a gateway class as the intermediate layer • Return if any handler handles the message • Some problems • Strong relationship of gateway class and concrete handlers. Difficult to adjust the order of handler • Cannot represent the relationship among handlers, they are all at the same level // server end code struct IFoo { virtual void bar(int) const = 0; virtual bool is_care(int) const = 0; }; struct gateway : IFoo { vector<IFoo*> fs_; mutable bool handled_ = false; virtual void bar(int n) const { for (size_t i = 0; i < fs_.size(); ++i) { if (fs_[i]->is_care(n)) { fs_[i].bar(n); break; } } } virtual bool is_care(int) const { return false; } void add_handler(IFoo* i) { fs_.push_back(i); } }; 4:54:14 AM 54
  • 55. Uncertain handler I, Cont • Code at call site // client end code struct zero_handler : IFoo { virtual void bar(int) const { cout << "zero handlern"; } virtual bool is_care(int n) const { return n == 0; } }; struct odd_handler : IFoo { virtual void bar(int) const { cout << "odd handlern"; } virtual bool is_care(int n) const { return n && n%2 != 0; } }; struct even_handler : IFoo { virtual void bar(int) const { cout << "even handlern"; } virtual bool is_care(int n) const { return n && n%2 == 0; } }; 4:54:14 AM 55 // client end code void call() { gateway gw; gw.add_handler(new odd_handler); gw.add_handler(new even_handler); gw.add_handler(new zero_handler); gw.bar(7); gw.bar(12); gw.bar(0); }
  • 56. Uncertain handler II • Second try • Using a link structure • If one handler does not care this message, it will routine the message to its successor if there is // server end code struct IFoo { virtual void bar(int) const = 0; }; struct IChainFoo : IFoo { IFoo* next_; explicit IChainFoo(IChainFoo* next = 0) : next_(next) {} virtual bool is_care(int n) const = 0; virtual void bar_impl() const = 0; virtual void bar(int n) const { if (is_care(n)) bar_impl(); else if (next_) next_->bar(n); } }; // client end code // concrete handle implementation ignored void call() { IChainFoo* chain = new odd_handler( new zero_handler( new even_handler())); chain->bar(7); chain->bar(12); chain->bar(0); } 4:54:14 AM 56
  • 57. The chain of responsibility • What’s that of linked message handling? The chain of responsibility pattern! • GoF: “Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it” 4:54:14 AM 57
  • 58. Load elephant into icebox I • The very old story, how can you load an elephant into a refrigerator? Three steps! • Open the door • Load the elephant • Close the door • We have right initial draft • Some comments • Foo defines the steps by implement bar() interface while providing default implementation (violate SRP) • Difficult to extend // server end code struct IFoo { virtual void bar() = 0; }; struct Foo : IFoo { void open_refrigerator() { cout << "open very big one ...n"; } void load_elephant() { cout << "load the elephant if it willn"; } void close_refrigerator() { cout << "close itn"; } virtual void bar() { open_refrigerator(); load_elephant(); close_refrigerator(); } }; // client end code void call() { IFoo* foo = new Foo; foo->bar(); } 4:54:14 AM 58
  • 59. Load elephant into icebox II • Refactor it to: • Push the implementation to client • Decouple the definition and implementation • So we have // server end code struct IFoo { virtual void bar() = 0; }; struct IFooImpl { virtual void open_refrigerator() = 0; virtual void load_elephant() = 0; virtual void close_refrigerator() = 0; }; struct Foo : IFoo { IFooImpl* impl_; explicit Foo(IFooImpl* i) : impl_(i) {} virtual void bar() { open_refrigerator(); load_elephant(); close_refrigerator(); } }; // client end code struct MySolution : IFooImpl { void open_refrigerator() { cout << "open very big one ...n"; } void load_elephant() { cout << "load the elephant if it willn"; } void close_refrigerator() { cout << "close itn"; } }; void call() { IFoo* foo = new Foo(new MySolution); foo->bar(); } 4:54:14 AM 59
  • 60. The template method • What’s that of base class defines skeleton while derived class provides implementation? The template method pattern! • GoF: “Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure” • Our example is a little different with the default structure as we push the implementation to client end • Similar to Bridge pattern but with different intent. 4:54:14 AM 60
  • 62. Handle message directly I • As behaviors of an object are decided by its state, so there is a typical implementation. • Possible issues • Difficult to extend. If we want to do something special action for state 4, we must modify the Foo implementation • Had better avoid switch/case or if/else if/else structure • Indeed, an actually bug there! // server end code struct Foo { int state_; void do_one() { cout << “action onen”; } void do_two() { cout << “action twon”; } void do_infinity() { cout << “action infinityn”; } void set(int s) { state_ = s; } void bar() { switch(state_) { case 1: do_one(); case 2: do_two(); default: do_infinity(); } } }; // client end code void call() { Foo foo; foo.set(2); foo.bar(); } 4:54:14 AM 62
  • 63. Handle message directly II • Refactor • Server end codes are written for interface only • Push actually functional codes to client end • Avoid switch/case by strong type // server end code struct IFoo_action { virtual void do_action() = 0; }; struct Foo { IFoo_action* action_; void set_action(IFoo_action* a) { action_ = a; } void bar() { action_->do_action(); } }; // client end code struct Action_for_one : IFoo_action { void do_action() { cout << "action onen"; } }; struct Action_for_two : IFoo_action { void do_action() { cout << "action twon"; } }; struct Action_for_infinity : IFoo_action { void do_action() { cout << "action infinityn"; } }; // client end code void call() { Foo foo; foo.set_action(new Action_for_two); foo.bar(); } 4:54:14 AM 63
  • 64. The strategy • What’s that? The strategy pattern! • GoF: “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it” 4:54:14 AM 64
  • 65. Enhance message handling I • There is an existed implementation of some types and you want to: • Reuse the implementation • Enhancement some specific behaviors, such as log, authentication, lock/unlock etc • The initial try is as right • Drawbacks • How about LSP? • Difficult to extend // server end code struct IFoo { virtual void bar() = 0; virtual void baz() = 0; }; struct Foo : IFoo { void bar() { cout << "action barn"; } void baz() { cout << "action bazn"; } }; // client end code void do_log(const char* msg) { cout << msg << "n"; } void call() { Foo foo; do_log("before call bar"); foo.bar(); } 4:54:14 AM 65
  • 66. Enhance message handling II • What does LSP say: • Wiki : “if S is a subtype of T, then objects of type T … may be replaced with objects of type S (i.e., objects of type S maybe substituted for objects of type T), without altering any of the desirable properties of that program (correctness, task performed, etc.)” • Now we can treat the Foo object and our customized MyFoo object in the same way // server end code struct IFoo { virtual void bar() = 0; }; struct Foo : IFoo { void bar() { cout << "action barn"; } }; // client end code void do_log(const char* msg) { cout << msg << "n"; } struct MyFoo : Foo { void bar() { do_log("before call bar"); Foo::bar(); } }; void call() { vector<IFoo*> vfs; vfo.push_back(new Foo); vfo.push_back(new MyFoo); for_each(vfs.begin(), vfs.end(), mem_fun(&IFoo::bar)); } 4:54:14 AM 66
  • 67. The decorator • What’s that? The decorator pattern! • GoF: “Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality” 4:54:14 AM 67
  • 68. Delegated message handling • Sometime, creating an object has a big overhead or just impossible • A distributed object maybe resident on another address space, so we need RPC infrastructure as the basis. • You have the right to use it only • Creating and destroying such object often is not desirable 4:54:14 AM 68
  • 69. The proxy (TODO) • What’s that? The proxy pattern! • GoF: “Provide a surrogate or placeholder for another object to control access to it” • Remote proxy. For distributed OO system • Virtual proxy. For lazy loading or initialization • Protected proxy. For access control • Smart pointer. For resource management or verification 4:54:14 AM 69
  • 70. The state (TODO) • What’s that? The state pattern! • GoF: “Allow an object to alter its behavior when its internal state changes. The object will appear to change its class” 4:54:14 AM 70
  • 71. Separated object serialize (I) • Image a ring buffer implementation • It gets store from client • It manipulates the buffer • Question: how to serialize the ring buffer object? • Answer one: serialize the buffer also • Bad solution. Client may have done this. Duplication! • Answer two: just serialize front/back status • Not good enough yet. After deserialized, the object status is not complete. 4:54:14 AM 71 // server end code struct RingBuffer { explicit RingBuffer(char* buff, size_t sz) : _size(sz), _buff(buff), _front(0), _back(_buff) {} void push_back(char value) { … } private: size_t _size; char* _buff; char* _front char* _back; }; // client end code void call() { char buff[1024]; RingBuffer rb(buff, 1024); const char* msg = “hello world!”; std::copy(msg, msg + strlen(msg), std::back_inserter<RingBuffer>(rb)); }
  • 72. Separated object serialize (II) • Answer three: delegate the serialization task client fully • Save internal status to a Memo object • Client can save this object • Client can restore this object later • Will 4:54:14 AM 72 // server end code struct RingBuffer { explicit RingBuffer(char* buff, size_t sz) {…} void push_back(char value) { … } struct Memo { size_t _sz; size_t _off; Memo(size_t sz, size_t off) : _sz(sz), _off(off) {} }; Memo* create_memo() const {…} void set_memo(Memo* m) {…} };
  • 73. The memento (TODO) • What’s that? The memento pattern! • GoF: “Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later” 4:54:14 AM 73
  • 75. The adapter • What’s that? The adapter pattern! • GoF: “Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces” 4:54:14 AM 75
  • 76. Special object including I • Many times, the object and its owner same type, that is, they implement the same interface and can be used interchangeable • File system. A folder can includes folders and files and they are all file system objects • Windows system. A dialog may include some buttons, edit boxes, combos etc. they are all windows indeed. • Image following client codes // client end code void call() { Dialog* dia = new Dialog("type your password"); dia->attach(new Button("OK")); dia->attach(new Button("Cancel")); dia->attach(new EditBox("Edit here")); dia->enable(); } 4:54:14 AM 76
  • 77. Special object including II // server end code struct IWin{ std::string name_; virtual void enable() = 0; // more windows properties }; struct Button : IWin{ Button(const char* name) { name_ = name; } void enable() { cout << "Button " << name_ << endl; } }; struct EditBox : IWin{ EditBox(const char* name) { name_ = name; } void enable() { cout << "EditBox " << name_ << endl; } }; struct Dialog : IWin{ Dialog(const char* name) { name_ = name; } void attach(IWin* w) { wins_.push_back(w); } void enable() { for_each(wins_.begin(), wins_.end(), mem_fun(&IWin::enable)); cout << "Dialog "" << name_ <<"" enablen"; } list<IWin*> wins_; }; • And this is the server end code • All concrete classes implement the same type • If one of them to be a container, it contains a list of pointer to that type • On message handling, before/after its own handling mechanism, it’ll forward the message to all objects it contains 4:54:14 AM 77
  • 78. The composite • What’s that? The composite pattern! • GoF: “Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly” • The pattern is seldom used alone, some other pattern make it more useful • Visitor. Add extra functionality to the class struct • Iterator. Enumerate and manipulate each subobjects • … 4:54:14 AM 78
  • 80. Implementation an interface I • Simple and straight, C++ provides directly support • There is a very big limitation however • The implementation is bond to server end code and change the implementation will definitely change server end code • How can we remove it? • Add new indirection layer • Push responsibility to client // server end code struct IFoo { virtual void bar() = 0; }; struct Foo : IFoo { void bar() { cout << "IFoo implementedn"; } }; // client end code void call() { Ifoo* foo = new Foo; foo->bar(); } 4:54:14 AM 80
  • 81. Implementation an interface II • Distinguish the type for interface and the type for implementation • Client end will provides the concrete implementation while server end only care about the interface to implementation • C++ usually calls this as p-impl idiom and use it to eliminate the strong header including relationship // server end code struct IFoo { virtual void bar() = 0; }; struct IFooImpl { virtual void bar_impl() = 0; }; struct Foo : public IFoo { IFooImpl* impl_; Foo(IFooImpl* i) : impl_(i) {} void bar() { impl_->bar_impl(); } }; // client end code struct MyImpl : public IFooImpl { virtual void bar_impl() { cout << "my IFoo implementationn"; } }; struct MyImplv2 : public IFooImpl { virtual void bar_impl() { cout << "my IFoo implementation v2n"; } }; void call() { vector<IFoo*> vf; vf.push_back(new Foo(new MyImpl)); vf.push_back(new Foo(new MyImplv2)); for_each(vf.begin(), vf.end(), mem_fun(&IFoo::bar)); } 4:54:14 AM 81
  • 82. The bridge • What’s that? The bridge pattern! • GoF: “Decouple an abstraction from its implementation so that the two can vary independently” 4:54:14 AM 82
  • 84. Using a package I • Usually, we use some classes of a package to do something • Typical, it’s the case that exporting some APIs for 3rd part use • Pitfalls • Sometimes you may not want expose the details of internal interfaces of server end code to client • Meanwhile, you don’t want to hide something that hard to use correctly or secrets • Client end code depends on the internal components of server end code, which make it’s very difficult to change server end implementation // server end code namespace domain { struct Foo { void do_foo() { cout << "Foo usedn"; } }; struct Bar { void do_bar() { cout << "Bar usedn"; } }; struct Baz { void do_baz() { cout << "Baz usedn"; } }; } // client end code void call() { domain::Foo f; domain::Bar b; domain::Baz z; f.do_foo(); b.do_bar(); z.do_baz(); } 4:54:14 AM 84
  • 85. Using a package II • Refactor it • Add another layer • Provide a new interface and standard the implementation of such common used tasks • The original interfaces may or may not available to client codes, depends on how your codes are used by client you expect • Client end code will not continue care about how the interfaces are implemented. They only use them! Simply and easily. // server end code namespace domain { struct Foo { void do_foo() { cout << "Foo usedn"; } }; struct Bar { void do_bar() { cout << "Bar usedn"; } }; struct Baz { void do_baz() { cout << "Baz usedn"; } }; struct FooBarBaz { Foo f_; Bar b_; Baz z_; void do_foobarbaz { f.do_foo(); b.do_bar(); z.do_baz(); } }; } // client end code void call() { domain::FooBarBaz fbz; fbz.do_foobarbaz (); } 4:54:14 AM 85
  • 86. The facade • What’s that? The façade pattern! • GoF: “Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use” • This is typical design method of package level interface. On the view of client end, the package it used is much like another objects while delegate all messages to its internal constructs. • Client end should always depend on the package interface instead of its internal implementation. If fine granularity controlling is needed, just export those necessary, wrapped subsystem interfaces. 4:54:14 AM 86
  • 87. The mediator (TODO) • What’s that? The mediator pattern! • GoF: “Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently” 4:54:14 AM 87
  • 88. The iterator (TODO) • What’s that? The iterator pattern! • GoF: “Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation” 4:54:14 AM 88
  • 89. The rest GoF patterns 4:54:14 AM 89
  • 90. Shared fine-grained object 4:54:14 AM 90
  • 91. The flyweight (TODO) • GoF: “Use sharing to support large numbers of fine-grained objects efficiently” 4:54:14 AM 91
  • 92. The interpreter (TODO) • GoF: “Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentences in the language” 4:54:14 AM 92