(1) Simple factory mode
Mainly used to create objects. Adding a new class will not affect the previous system code. The core idea is to use a factory to generate different classes according to the input conditions, and then get different results according to the virtual functions of different classes.
GOOD: applicable to different situations when creating different classes
BUG: the client must know the base class and factory class, and the coupling is poor
(factory class and base class are related)
Example:
//Base class class COperation { public: int m_nFirst; int m_nSecond; virtual double GetResult() { double dResult=0; return dResult; } }; //addition class AddOperation : public COperation { public: virtual double GetResult() { return m_nFirst+m_nSecond; } }; //subtraction class SubOperation : public COperation { public: virtual double GetResult() { return m_nFirst-m_nSecond; } }; //Factory class class CCalculatorFactory { public: static COperation* Create(char cOperator); }; COperation* CCalculatorFactory::Create(char cOperator) { COperation *oper; //In C #, you can use reflection to cancel the switch used in judgment. What is used in C + +? RTTI?? switch (cOperator) { case '+': oper=new AddOperation(); break; case '-': oper=new SubOperation(); break; default: oper=new AddOperation(); break; } return oper; }
client
int main() { int a,b; cin>>a>>b; COperation * op=CCalculatorFactory::Create('-'); op->m_nFirst=a; op->m_nSecond=b; cout<<op->GetResult()<<endl; return 0; }
(2) Strategy mode
Define algorithm families and package them separately, so that they can be replaced with each other, so that algorithm changes will not affect users
GOOD: the members in the class are mainly methods, and the algorithm changes frequently; It simplifies unit testing (because each algorithm has its own class and can be tested separately through its own interface).
The policy mode is basically the same as the simple factory mode, but the simple factory mode can only solve the problem of object creation. The policy mode should be used for frequently changing algorithms.
BUG: the client needs to make a judgment
example
//Policy base class class COperation { public: int m_nFirst; int m_nSecond; virtual double GetResult() { double dResult=0; return dResult; } }; //Policy concrete class - addition class class AddOperation : public COperation { public: AddOperation(int a,int b) { m_nFirst=a; m_nSecond=b; } virtual double GetResult() { return m_nFirst+m_nSecond; } }; class Context { private: COperation* op; public: Context(COperation* temp) { op=temp; } double GetResult() { return op->GetResult(); } }; //client int main() { int a,b; char c; cin>>a>>b; cout<<"Please enter operator:; cin>>c; switch(c) { case '+': Context *context=new Context(new AddOperation(a,b)); cout<<context->GetResult()<<endl; break; default: break; } return 0; }
Combination of strategy and factory
GOOD: the client only needs to access the Context class without knowing any other class information, realizing low coupling.
On the basis of the above example, modify the following contents
class Context { private: COperation* op; public: Context(char cType) { switch (cType) { case '+': op=new AddOperation(3,8); break; default: op=new AddOperation(); break; } } double GetResult() { return op->GetResult(); } }; //client int main() { int a,b; cin>>a>>b; Context *test=new Context('+'); cout<<test->GetResult()<<endl; return 0; }
Single responsibility principle
As far as a class is concerned, there should be only one reason for its change.
If a class undertakes too many responsibilities, it is equivalent to coupling these responsibilities together. The change of one responsibility may weaken or inhibit the class's ability to complete other responsibilities. This coupling will lead to fragile design. When changes occur, the design will suffer unexpected damage.
If you can think of more than one motivation to change a class, the class has more than one responsibility.
Open closed principle
Software entities can be extended, but cannot be modified. That is, they are open to expansion and closed to modification. In the face of requirements, the changes to the program are completed by adding code, rather than changing the existing code.
When changes occur, we create abstractions to isolate similar changes in the future.
The open closed principle is the core of object-oriented. Developers should abstract the frequently changing part of the program, and refuse to deliberately abstract and immature abstraction of any part.
Richter substitution principle
If a software entity uses a parent class, it must apply to its child classes. Moreover, it cannot detect the difference between parent objects and child objects. That is, in software, if the parent class is replaced with a child class, the behavior of the program does not change.
Subtypes must be able to replace their parent type.
Dependence Inversion Principle
Abstraction should not depend on details, and details should depend on abstraction, that is, programming for interfaces, not for implementations.
High level modules cannot rely on low-level modules, and both should rely on abstraction.
The dependency inversion principle is an object-oriented sign. It doesn't matter which language to write the program. If you consider how to program for abstract rather than details, that is, all dependencies of the program terminate in abstract classes or interfaces, that is, object-oriented design, and vice versa, procedural design.
(3) Decoration mode
Dynamically add some additional responsibilities to an object (unimportant functions are only performed occasionally). In terms of adding functions, the decoration mode is more flexible than generating subclasses. The construction process is unstable and controlled in series in the correct order.
GOOD: when you add new code to an old class, you usually add core responsibilities or main behaviors. When you need to add only specific functions that will be executed under specific circumstances (simply not the functions of the core application) Decoration mode is to put the additional functions to be added in separate classes, and let this class contain the objects to be decorated. When it needs to be executed, the client can selectively and sequentially wrap the objects with decoration functions.
example
#include <string> #include <iostream> using namespace std; //people class Person { private: string m_strName; public: Person(string strName) { m_strName=strName; } Person(){} virtual void Show() { cout<<"Dressed up as:"<<m_strName<<endl; } }; //Decoration class class Finery :public Person { protected: Person* m_component; public: void Decorate(Person* component) { m_component=component; } virtual void Show() { m_component->Show(); } }; //T-shirt class TShirts: public Finery { public: virtual void Show() { cout<<"T Shirts"<<endl; m_component->Show(); } }; //trousers class BigTrouser :public Finery { public: virtual void Show() { cout<<" Big Trouser"<<endl; m_component->Show(); } }; //client int main() { Person *p=new Person("petty thief"); BigTrouser *bt=new BigTrouser(); TShirts *ts=new TShirts(); bt->Decorate(p); ts->Decorate(bt); ts->Show(); return 0; }
(4) Agent mode
GOOD: remote proxy can hide the fact that an object is in different address spaces
Virtual proxy: use proxy to store objects that need to be instantiated for a long time
Security proxy: used to control the access rights of real objects
Smart reference: when a real object is called, the proxy handles something else
Example:
#include <string> #include <iostream> using namespace std; //Define interface class Interface { public: virtual void Request()=0; }; //Real class class RealClass : public Interface { public: virtual void Request() { cout<<"Real request"<<endl; } }; //proxy class class ProxyClass : public Interface { private: RealClass* m_realClass; public: virtual void Request() { m_realClass= new RealClass(); m_realClass->Request(); delete m_realClass; } };
client:
int main() { ProxyClass* test=new ProxyClass(); test->Request(); return 0; }
(5) Factory method model
GOOD: fixed that the simple factory mode does not comply with the open closed principle. The factory method mode moves the selection judgment to the client for implementation. If you want to add new functions, you don't need to modify the original class, you can directly modify the client.
Example:
#include <string> #include <iostream> using namespace std; //Instance base class, equivalent to product (no abstraction for convenience) class LeiFeng { public: virtual void Sweep() { cout<<"Lei Feng sweeps the floor"<<endl; } }; //A college student learning from Lei Feng is equivalent to concrete product class Student: public LeiFeng { public: virtual void Sweep() { cout<<"College students sweep the floor"<<endl; } }; //Volunteers who learn from Lei Feng are equivalent to concrete product class Volenter: public LeiFeng { public : virtual void Sweep() { cout<<"volunteer"<<endl; } }; //Workshop base Creator class LeiFengFactory { public: virtual LeiFeng* CreateLeiFeng() { return new LeiFeng(); } }; //Workshop specific category class StudentFactory : public LeiFengFactory { public : virtual LeiFeng* CreateLeiFeng() { return new Student(); } }; class VolenterFactory : public LeiFengFactory { public: virtual LeiFeng* CreateLeiFeng() { return new Volenter(); } }; //client int main() { LeiFengFactory *sf=new LeiFengFactory(); LeiFeng *s=sf->CreateLeiFeng(); s->Sweep(); delete s; delete sf; return 0; }
(6) Prototype mode
GOOD: create another customizable object from one object without knowing any creation details. It can improve the creation performance. To put it bluntly, COPY an object completely.
Example:
#include<iostream> #include <vector> #include <string> using namespace std; class Prototype //Abstract base class { private: string m_strName; public: Prototype(string strName){ m_strName = strName; } Prototype() { m_strName = " "; } void Show() { cout<<m_strName<<endl; } virtual Prototype* Clone() = 0 ; } ; // class ConcretePrototype1 class ConcretePrototype1 : public Prototype { public: ConcretePrototype1(string strName) : Prototype(strName){} ConcretePrototype1(){} virtual Prototype* Clone() { ConcretePrototype1 *p = new ConcretePrototype1() ; *p = *this ; //copy object return p ; } } ; // class ConcretePrototype2 class ConcretePrototype2 : public Prototype { public: ConcretePrototype2(string strName) : Prototype(strName){} ConcretePrototype2(){} virtual Prototype* Clone() { ConcretePrototype2 *p = new ConcretePrototype2() ; *p = *this ; //copy object return p ; } } ; //client int main() { ConcretePrototype1* test = new ConcretePrototype1("Xiao Wang"); ConcretePrototype2* test2 = (ConcretePrototype2*)test->Clone(); test->Show(); test2->Show(); return 0; }
(7) Template method pattern
GOOD: transfer the unchanged code parts to the parent class, and leave the variable code in virtual for subclass rewriting
Example:
#include<iostream> #include <vector> #include <string> using namespace std; class AbstractClass { public: void Show() { cout<<"I am"<<GetName()<<endl; } protected: virtual string GetName()=0; }; class Naruto : public AbstractClass { protected: virtual string GetName() { return "The most handsome six generations in the history of Huoying---set the Thames a great coup naruto"; } }; class OnePice : public AbstractClass { protected: virtual string GetName() { return "I'm a big pirate who does all kinds of evil---Monkey D Luffy"; } }; //client int main() { Naruto* man = new Naruto(); man->Show(); OnePice* man2 = new OnePice(); man2->Show(); return 0; }
Dimitt's law
If two classes do not communicate directly, the two classes should not interact directly. If a class needs to call a method of another class, it can forward the call through the third class.
In the structural design of classes, each class should minimize the access rights of members.
This rule is strongly reflected in the later adapter mode and interpretation mode.
(8) Appearance mode
GOOD: provide a consistent interface for a group of interfaces of the subsystem, making it more convenient for users to use.
Example:
#include<iostream> #include <string> using namespace std; class SubSysOne { public: void MethodOne() { cout<<"Method 1"<<endl; } }; class SubSysTwo { public: void MethodTwo() { cout<<"Method 2"<<endl; } }; class SubSysThree { public: void MethodThree() { cout<<"Method 3"<<endl; } }; //Appearance class class Facade { private: SubSysOne* sub1; SubSysTwo* sub2; SubSysThree* sub3; public: Facade() { sub1 = new SubSysOne(); sub2 = new SubSysTwo(); sub3 = new SubSysThree(); } ~Facade() { delete sub1; delete sub2; delete sub3; } void FacadeMethod() { sub1->MethodOne(); sub2->MethodTwo(); sub3->MethodThree(); } }; //client int main() { Facade* test = new Facade(); test->FacadeMethod(); return 0; }
(9) Builder mode (generator mode)
GOOD: applicable when the algorithm for creating complex objects should be independent of the components of the object and how they are assembled.
Example:
#include <string> #include <iostream> #include <vector> using namespace std; //Final product category class Product { private: vector<string> m_product; public: void Add(string strtemp) { m_product.push_back(strtemp); } void Show() { vector<string>::iterator p=m_product.begin(); while (p!=m_product.end()) { cout<<*p<<endl; p++; } } }; //Builder base class class Builder { public: virtual void BuilderA()=0; virtual void BuilderB()=0; virtual Product* GetResult()=0; }; //The first construction method class ConcreteBuilder1 : public Builder { private: Product* m_product; public: ConcreteBuilder1() { m_product=new Product(); } virtual void BuilderA() { m_product->Add("one"); } virtual void BuilderB() { m_product->Add("two"); } virtual Product* GetResult() { return m_product; } }; //The second construction method class ConcreteBuilder2 : public Builder { private: Product * m_product; public: ConcreteBuilder2() { m_product=new Product(); } virtual void BuilderA() { m_product->Add("A"); } virtual void BuilderB() { m_product->Add("B"); } virtual Product* GetResult() { return m_product; } }; //Conductor class class Direct { public: void Construct(Builder* temp) { temp->BuilderA(); temp->BuilderB(); } }; //client int main() { Direct *p=new Direct(); Builder* b1=new ConcreteBuilder1(); Builder* b2=new ConcreteBuilder2(); p->Construct(b1); //Call the first method Product* pb1=b1->GetResult(); pb1->Show(); p->Construct(b2); //Call the second method Product * pb2=b2->GetResult(); pb2->Show(); return 0; } Example 2 (in fact, this example should be mentioned earlier): #include <string> #include <iostream> #include <vector> using namespace std; class Person { public: virtual void CreateHead()=0; virtual void CreateHand()=0; virtual void CreateBody()=0; virtual void CreateFoot()=0; }; class ThinPerson : public Person { public: virtual void CreateHead() { cout<<"thin head"<<endl; } virtual void CreateHand() { cout<<"thin hand"<<endl; } virtual void CreateBody() { cout<<"thin body"<<endl; } virtual void CreateFoot() { cout<<"thin foot"<<endl; } }; class ThickPerson : public Person { public: virtual void CreateHead() { cout<<"ThickPerson head"<<endl; } virtual void CreateHand() { cout<<"ThickPerson hand"<<endl; } virtual void CreateBody() { cout<<"ThickPerson body"<<endl; } virtual void CreateFoot() { cout<<"ThickPerson foot"<<endl; } }; //Conductor class class Direct { private: Person* p; public: Direct(Person* temp) { p = temp;} void Create() { p->CreateHead(); p->CreateBody(); p->CreateHand(); p->CreateFoot(); } }; //Client code: int main() { Person *p=new ThickPerson(); Direct *d= new Direct(p); d->Create(); delete d; delete p; return 0; }
(10) Observer mode
GOOD: defines a one to many relationship, which allows multiple observers (company employees) to listen to a subject object (secretary) at the same time. When the status of the subject object changes, all observers will be notified so that they can update themselves.
Example:
#include <string> #include <iostream> #include <vector> using namespace std; class Secretary; //Colleagues looking at stocks (observers, observers) class StockObserver { private: string name; Secretary* sub; public: StockObserver(string strname,Secretary* strsub) { name=strname; sub=strsub; } void Update(); }; //Secretary (subject object, notifier) class Secretary { private: vector<StockObserver> observers; public: string action; void Add(StockObserver ob) { observers.push_back(ob); } void Notify() { vector<StockObserver>::iterator p = observers.begin(); while (p!=observers.end()) { (*p).Update(); p++; } } }; void StockObserver::Update() { cout<<name<<":"<<sub->action<<",Stop playing with stocks and start working"<<endl; } //client int main() { Secretary *p=new Secretary(); //Create Notifier //Observer StockObserver *s1= new StockObserver("petty thief",p); StockObserver *s2 = new StockObserver("Xiao Zhao",p); //Join notification queue p->Add(*s1); p->Add(*s2); //event p->action="Here comes the boss"; //notice p->Notify(); return 0; }
Example:
#include <string> #include <iostream> #include <vector> using namespace std; class SecretaryBase; //Abstract observer class CObserverBase { protected: string name; SecretaryBase* sub; public: CObserverBase(string strname,SecretaryBase* strsub) { name=strname; sub=strsub; } virtual void Update()=0; }; //Specific observers look at the stock market class StockObserver : public CObserverBase { public: StockObserver(string strname,SecretaryBase* strsub) : CObserverBase(strname,strsub) { } virtual void Update(); }; //Specific observers, look at the NBA class NBAObserver : public CObserverBase { public: NBAObserver(string strname,SecretaryBase* strsub) : CObserverBase(strname,strsub){} virtual void Update(); }; //Abstract Notifier class SecretaryBase { public: string action; vector<CObserverBase*> observers; public: virtual void Attach(CObserverBase* observer)=0; virtual void Notify()=0; }; //Specific Notifier class Secretary :public SecretaryBase { public: void Attach(CObserverBase* ob) { observers.push_back(ob); } void Notify() { vector<CObserverBase*>::iterator p = observers.begin(); while (p!=observers.end()) { (*p)->Update(); p++; } } }; void StockObserver::Update() { cout<<name<<":"<<sub->action<<",Stop playing with stocks and start working"<<endl; } void NBAObserver::Update() { cout<<name<<":"<<sub->action<<",Don't look NBA Yes, the boss is here"<<endl; }
client:
int main() { SecretaryBase *p=new Secretary(); //Create observer //Observed object CObserverBase *s1= new NBAObserver("petty thief",p); CObserverBase *s2 = new StockObserver("Xiao Zhao",p); //Join the observation queue p->Attach(s1); p->Attach(s2); //event p->action="Here comes the boss"; //notice p->Notify(); return 0; }
(11) Abstract factory pattern
GOOD: defines an interface that creates a series of related or interdependent interfaces without specifying their specific classes.
Used to exchange product series, such as access - > sql server;
The specific class name of the product is separated by the implementation of the specific factory
Example:
#include <string> #include <iostream> #include <vector> using namespace std; //User abstract interface class IUser { public : virtual void GetUser()=0; virtual void InsertUser()=0; }; //Department abstract interface class IDepartment { public: virtual void GetDepartment()=0; virtual void InsertDepartment()=0; }; //ACCESS user class CAccessUser : public IUser { public: virtual void GetUser() { cout<<"Access GetUser"<<endl; } virtual void InsertUser() { cout<<"Access InsertUser"<<endl; } }; //ACCESS Department class CAccessDepartment : public IDepartment { public: virtual void GetDepartment() { cout<<"Access GetDepartment"<<endl; } virtual void InsertDepartment() { cout<<"Access InsertDepartment"<<endl; } }; //SQL user class CSqlUser : public IUser { public: virtual void GetUser() { cout<<"Sql User"<<endl; } virtual void InsertUser() { cout<<"Sql User"<<endl; } }; //SQL department class class CSqlDepartment: public IDepartment { public: virtual void GetDepartment() { cout<<"sql getDepartment"<<endl; } virtual void InsertDepartment() { cout<<"sql insertdepartment"<<endl; } }; //Abstract factory class IFactory { public: virtual IUser* CreateUser()=0; virtual IDepartment* CreateDepartment()=0; }; //ACCESS factory class AccessFactory : public IFactory { public: virtual IUser* CreateUser() { return new CAccessUser(); } virtual IDepartment* CreateDepartment() { return new CAccessDepartment(); } }; //SQL factory class SqlFactory : public IFactory { public: virtual IUser* CreateUser() { return new CSqlUser(); } virtual IDepartment* CreateDepartment() { return new CSqlDepartment(); } };
client:
int main() { IFactory* factory= new SqlFactory(); IUser* user=factory->CreateUser(); IDepartment* depart = factory->CreateDepartment(); user->GetUser(); depart->GetDepartment(); return 0; }
(12) State mode
GOOD: when the behavior of an object depends on its state and it must change its behavior according to the state at runtime, the state mode can be considered.
example
#include <iostream> using namespace std; class Work; class ForenoonState; class NoonState; class State { public: virtual void WriteProgram(Work* w)=0; }; class Work { private: State* current; public: double hour; public: Work(); void SetState(State* temp) { current =temp; } void Writeprogram() { current->WriteProgram(this); } }; class NoonState :public State { public: virtual void WriteProgram(Work* w) { cout<<"execute"<<endl; if((w->hour)<13) cout<<"Not bad"<<endl; else cout<<"No, I'd better go to bed"<<endl; } }; class ForenoonState : public State { public: virtual void WriteProgram(Work* w) { if((w->hour)<12) cout<<"Now the spirit is invincible"<<endl; else { w->SetState(new NoonState()); w->Writeprogram(); //Pay attention to adding this sentence } } }; Work::Work() { current = new ForenoonState(); }
client:
int main() { Work* mywork=new Work(); mywork->hour=9; mywork->Writeprogram(); mywork->hour = 14; mywork->Writeprogram(); return 0; }
(13) Adapter mode
GOOD: when both sides are not suitable for modification, you can consider using the adapter mode
Example:
#include <iostream> using namespace std; class Target { public: virtual void Request() { cout<<"Ordinary request"<<endl; } }; class Adaptee { public: void SpecificalRequest() { cout<<"Special request"<<endl; } }; class Adapter :public Target { private: Adaptee* ada; public: virtual void Request() { ada->SpecificalRequest(); Target::Request(); } Adapter() { ada=new Adaptee(); } ~Adapter() { delete ada; } };
client:
int main() { Adapter * ada=new Adapter(); ada->Request(); delete ada; return 0; }
Example 2
#include <iostream> #include <string> using namespace std; class Player { protected: string name; public: Player(string strName) { name = strName; } virtual void Attack()=0; virtual void Defense()=0; }; class Forwards : public Player { public: Forwards(string strName):Player(strName){} public: virtual void Attack() { cout<<name<<"Forward attack"<<endl; } virtual void Defense() { cout<<name<<"Forward defense"<<endl; } }; class Center : public Player { public: Center(string strName):Player(strName){} public: virtual void Attack() { cout<<name<<"Midfield attack"<<endl; } virtual void Defense() { cout<<name<<"Defensive midfielder "<<endl; } }; //Translation for midfield class TransLater: public Player { private: Center *player; public: TransLater(string strName):Player(strName) { player = new Center(strName); } virtual void Attack() { player->Attack(); } virtual void Defense() { player->Defense(); } };
client
int main() { Player *p=new TransLater("petty thief"); p->Attack(); return 0; }
(14) Memo mode
GOOD: on the premise of not destroying encapsulation, capture the internal state of an object and save the state outside the object, so that the later object state can be restored to the previously saved state.
It is applicable to classes with complex functions but need to record or maintain attribute history; Or when the attributes to be saved are only a small part of many attributes, the Originator can restore to the previous state according to the saved Memo.
Example:
#include <iostream> #include <string> using namespace std; class Memo; //Initiate human class Originator { public: string state; Memo* CreateMemo(); void SetMemo(Memo* memo); void Show() { cout<<"Status:"<<state<<endl; } }; //Memo class class Memo { public: string state; Memo(string strState) { state= strState; } }; Memo* Originator::CreateMemo() { return new Memo(state); } void Originator::SetMemo(Memo* memo) { state = memo->state; } //Manager class class Caretaker { public: Memo* memo; };
client:
int main() { Originator* on=new Originator(); on->state = "on"; on->Show(); Caretaker* c= new Caretaker(); c->memo = on->CreateMemo(); on->state = "off"; on->Show(); on->SetMemo(c->memo); on->Show(); return 0; }
(15) Combination mode
GOOD: the whole and part can be treated consistently (for example, copying a text, a paragraph of text and an article in WORD are the same operation)
Example:
#include <iostream> #include <string> #include <vector> using namespace std; class Component { public: string m_strName; Component(string strName) { m_strName = strName; } virtual void Add(Component* com)=0; virtual void Display(int nDepth)=0; }; class Leaf : public Component { public: Leaf(string strName): Component(strName){} virtual void Add(Component* com) { cout<<"leaf can't add"<<endl; } virtual void Display(int nDepth) { string strtemp; for(int i=0; i < nDepth; i++) { strtemp+="-"; } strtemp += m_strName; cout<<strtemp<<endl; } }; class Composite : public Component { private: vector<Component*> m_component; public: Composite(string strName) : Component(strName){} virtual void Add(Component* com) { m_component.push_back(com); } virtual void Display(int nDepth) { string strtemp; for(int i=0; i < nDepth; i++) { strtemp+="-"; } strtemp += m_strName; cout<<strtemp<<endl; vector<Component*>::iterator p=m_component.begin(); while (p!=m_component.end()) { (*p)->Display(nDepth+2); p++; } } }; //client #include "Model.h" int main() { Composite* p=new Composite("Xiao Wang"); p->Add(new Leaf("petty thief")); p->Add(new Leaf("Xiao Zhao")); Composite* p1 = new Composite("Little five"); p1->Add(new Leaf("Junior")); p->Add(p1); p->Display(1); return 0; }
Example 2
#include <iostream> #include <string> #include <vector> using namespace std; class Company { protected: string m_strName; public: Company(string strName) { m_strName = strName; } virtual void Add(Company* c)=0; virtual void Display(int nDepth)=0; virtual void LineOfDuty()=0; }; class ConcreteCompany: public Company { private: vector<Company*> m_company; public: ConcreteCompany(string strName):Company(strName){} virtual void Add(Company* c) { m_company.push_back(c); } virtual void Display(int nDepth) { string strtemp; for(int i=0; i < nDepth; i++) { strtemp += "-"; } strtemp +=m_strName; cout<<strtemp<<endl; vector<Company*>::iterator p=m_company.begin(); while (p!=m_company.end()) { (*p)->Display(nDepth+2); p++; } } virtual void LineOfDuty() { vector<Company*>::iterator p=m_company.begin(); while (p!=m_company.end()) { (*p)->LineOfDuty(); p++; } } }; class HrDepartment : public Company { public: HrDepartment(string strname) : Company(strname){} virtual void Display(int nDepth) { string strtemp; for(int i = 0; i < nDepth; i++) { strtemp += "-"; } strtemp += m_strName; cout<<strtemp<<endl; } virtual void Add(Company* c) { cout<<"error"<<endl; } virtual void LineOfDuty() { cout<<m_strName<<":Recruitment of talents"<<endl; } }; //client: int main() { ConcreteCompany *p = new ConcreteCompany("Tsinghua University"); p->Add(new HrDepartment("Talent Department of Tsinghua University")); ConcreteCompany *p1 = new ConcreteCompany("faculty of Mathematics"); p1->Add(new HrDepartment("Talent Department of Mathematics Department")); ConcreteCompany *p2 = new ConcreteCompany("physics department"); p2->Add(new HrDepartment("Department of Physics")); p->Add(p1); p->Add(p2); p->Display(1); p->LineOfDuty(); return 0; }
(16) Iterator mode
GOOD: provides a way to access the elements of a convergent object sequentially without exposing the internal representation of the object.
It provides unified interfaces for traversing different aggregation structures, such as start, next, end, current, etc.
(17) Singleton mode
GOOD: ensure that a class has only one instance and provide a global access point to access it
Example:
#include <iostream> #include <string> #include <vector> using namespace std; class Singelton { private: Singelton(){} static Singelton* singel; public: static Singelton* GetInstance() { if(singel == NULL) { singel = new Singelton(); } return singel; } }; Singelton* Singelton::singel = NULL;//Note that static variables are initialized out of class
client:
int main() { Singelton* s1=Singelton::GetInstance(); Singelton* s2=Singelton::GetInstance(); if(s1 == s2) cout<<"ok"<<endl; else cout<<"no"<<endl; return 0; }
(18) Bridging mode
GOOD: separate the abstract part from the implementation part so that they can change independently.
What we mean here is not to separate the abstract base class from the concrete class, but that the real system may have multi angle classification, and each classification may change. Then separate these multi angles, let them change independently, and reduce the coupling between them. That is, if inheritance can not realize the "open closed principle", we should consider using the bridge mode. The following example: let "mobile phone" be classified by brand or
Example:
#include <iostream> #include <string> #include <vector> using namespace std; //Mobile software class HandsetSoft { public: virtual void Run()=0; }; //Game software class HandsetGame : public HandsetSoft { public: virtual void Run() { cout<<"Running mobile games"<<endl; } }; //Address book software class HandSetAddressList : public HandsetSoft { public: virtual void Run() { cout<<"Mobile phone address book"<<endl; } }; //Mobile phone brand class HandsetBrand { protected: HandsetSoft* m_soft; public: void SetHandsetSoft(HandsetSoft* temp) { m_soft = temp; } virtual void Run()=0; }; //M Brand class HandsetBrandM : public HandsetBrand { public: virtual void Run() { m_soft->Run(); } }; //Brand N class HandsetBrandN : public HandsetBrand { public: virtual void Run() { m_soft->Run(); } }; //client int main() { HandsetBrand *brand; brand = new HandsetBrandM(); brand->SetHandsetSoft(new HandsetGame()); brand->Run(); brand->SetHandsetSoft(new HandSetAddressList()); brand->Run(); return 0; }
(19) Command mode
GOOD: first, establish a command queue; 2, Commands can be logged; 3, The party receiving the request may refuse; 4, Adding a new command class does not affect other classes;
Command mode separates the object that requests an operation from the object that knows how to perform an operation
Example:
#include <iostream> #include <string> #include <vector> using namespace std; //Barbecue Chef class Barbucer { public: void MakeMutton() { cout<<"roast mutton"<<endl; } void MakeChickenWing() { cout<<"Roast chicken wings"<<endl; } }; //Abstract command class class Command { protected: Barbucer* receiver; public: Command(Barbucer* temp) { receiver = temp; } virtual void ExecuteCmd()=0; }; //Roast mutton command class BakeMuttonCmd : public Command { public: BakeMuttonCmd(Barbucer* temp) : Command(temp){} virtual void ExecuteCmd() { receiver->MakeMutton(); } }; //Roast chicken wings class ChickenWingCmd : public Command { public: ChickenWingCmd(Barbucer* temp) : Command(temp){} virtual void ExecuteCmd() { receiver->MakeChickenWing(); } }; //Waiter class class Waiter { protected: vector<Command*> m_commandList; public: void SetCmd(Command* temp) { m_commandList.push_back(temp); cout<<"Add order"<<endl; } //Notification execution void Notify() { vector<Command*>::iterator p=m_commandList.begin(); while(p!=m_commandList.end()) { (*p)->ExecuteCmd(); p++; } } }; //client int main() { //Add barbecue chef, menu, waiter and other customers in the store Barbucer* barbucer=new Barbucer(); Command* cmd= new BakeMuttonCmd(barbucer); Command* cmd2=new ChickenWingCmd(barbucer); Waiter* girl = new Waiter(); //order girl->SetCmd(cmd); girl->SetCmd(cmd2); //Waiter notification girl->Notify(); return 0; }
(20) Responsibility chain model
GOOD: make multiple objects have the opportunity to process the request, so as to avoid the coupling relationship between the sender and receiver of the request. Connect the object into a chain and pass the request along the chain until an object handles it.
Example:
#include <iostream> #include <string> #include <vector> using namespace std; //request class Request { public: string m_strContent; int m_nNumber; }; //controller class Manager { protected: Manager* manager; string name; public: Manager(string temp) { name = temp; } void SetSuccessor(Manager* temp) { manager = temp; } virtual void GetRequest(Request* request) = 0; }; //manager class CommonManager : public Manager { public: CommonManager(string strTemp) : Manager(strTemp){} virtual void GetRequest(Request* request) { if ( request->m_nNumber>=0 && request->m_nNumber<10 ) { cout<<name<<"Handled"<<request->m_nNumber<<"Requests"<<endl; } else { manager->GetRequest(request); } } }; //chief inspector class MajorDomo : public Manager { public: MajorDomo(string name) : Manager(name){} virtual void GetRequest(Request* request) { if(request->m_nNumber>=10) { cout<<name<<"Handled"<<request->m_nNumber<<"Requests"<<endl; } } }; //client int main() { Manager * common = new CommonManager("Manager Zhang"); Manager * major = new MajorDomo("Director Li"); common->SetSuccessor(major); Request* req = new Request(); req->m_nNumber = 33; common->GetRequest(req); req->m_nNumber = 3; common->GetRequest(req); return 0; }
21) Intermediary model
GOOD: a mediation object is used to encapsulate a series of object interactions. The mediator makes the objects do not need to show mutual references, so as to reduce the coupling; And the interaction between them can be changed independently.
Example:
#include <iostream> #include <string> #include <vector> using namespace std; class Colleague; //Intermediary class class Mediator { public: virtual void Send(string message,Colleague* col) = 0; }; //Abstract colleague class class Colleague { protected: Mediator* mediator; public: Colleague(Mediator* temp) { mediator = temp; } }; //Colleague 1 class Colleague1 : public Colleague { public: Colleague1(Mediator* media) : Colleague(media){} void Send(string strMessage) { mediator->Send(strMessage,this); } void Notify(string strMessage) { cout<<"As soon as my colleague got the news"<<strMessage<<endl; } }; //Colleague 2 class Colleague2 : public Colleague { public: Colleague2(Mediator* media) : Colleague(media){} void Send(string strMessage) { mediator->Send(strMessage,this); } void Notify(string strMessage) { cout<<"Colleague 2 got the news"<<strMessage<<endl; } }; //Specific intermediary class class ConcreteMediator : public Mediator { public: Colleague1 * col1; Colleague2 * col2; virtual void Send(string message,Colleague* col) { if(col == col1) col2->Notify(message); else col1->Notify(message); } }; //client: int main() { ConcreteMediator * m = new ConcreteMediator(); //Let colleagues know the intermediary Colleague1* col1 = new Colleague1(m); Colleague2* col2 = new Colleague2(m); //Let the intermediary know specific colleagues m->col1 = col1; m->col2 = col2; col1->Send("have you had dinner"); col2->Send("I haven't eaten yet. Will you treat me?"); return 0; }
(22) Sharing element mode
GOOD: use sharing technology to effectively support a large number of fine-grained objects (for C + +, it means sharing a memory block, and the object pointer points to the same place).
If an application uses a large number of objects and these objects cause great storage overhead, it should be considered.
In addition, most states of objects can be external states. If you delete the external states of objects, you can replace multiple groups of objects with fewer shared objects. At this time, you can consider using shared objects.
Example:
#include <iostream> #include <string> #include <vector> using namespace std; //Abstract website class WebSite { public: virtual void Use()=0; }; //Specific shared websites class ConcreteWebSite : public WebSite { private: string name; public: ConcreteWebSite(string strName) { name = strName; } virtual void Use() { cout<<"Site classification:"<<name<<endl; } }; //Unshared sites class UnShareWebSite : public WebSite { private: string name; public: UnShareWebSite(string strName) { name = strName; } virtual void Use() { cout<<"Unshared sites:"<<name<<endl; } }; //The site factory class is used to store shared WebSite objects class WebFactory { private: vector<WebSite*> websites; public: WebSite* GetWeb() { vector<WebSite*>::iterator p = websites.begin(); return *p; } WebFactory() { websites.push_back(new ConcreteWebSite("test")); } }; //client int main() { WebFactory* f= new WebFactory(); WebSite* ws= f->GetWeb(); ws->Use(); WebSite* ws2 = f->GetWeb(); ws2->Use(); //Unshared classes WebSite* ws3 = new UnShareWebSite("test"); ws3->Use(); return 0; }
(23) Interpreter mode
GOOD: usually, when a language needs interpretation and execution, and you can represent the sentences in the language as an abstract syntax tree, you can use the Interpreter pattern.
Example:
#include <iostream> #include <string> #include <vector> using namespace std; class Context; class AbstractExpression { public: virtual void Interpret(Context* context)=0; }; class Expression : public AbstractExpression { public: virtual void Interpret(Context* context) { cout<<"Terminal interpreter"<<endl; }; }; class NonterminalExpression : public AbstractExpression { public: virtual void Interpret(Context* context) { cout<<"Non terminal interpreter"<<endl; } }; class Context { public: string input; string output; }; //client int main() { Context* context = new Context(); vector<AbstractExpression*> express; express.push_back(new Expression()); express.push_back(new NonterminalExpression()); express.push_back(new NonterminalExpression()); vector<AbstractExpression*>::iterator p = express.begin(); while (p!= express.end()) { (*p)->Interpret(context); p++; } return 0; }
(24) Visitor mode
GOOD: suitable for systems with stable data structure. It separates the data structure from the operations acting on the data structure, making the operation set
Advantages: adding new operations is easy, because adding new operations is equivalent to adding a visitor. The visitor pattern focuses the relevant behaviors into a visitor object
Example:
#include <iostream> #include <string> #include <vector> using namespace std; class Man; class Woman; //behavior class Action { public: virtual void GetManConclusion(Man* concreteElementA)=0; virtual void GetWomanConclusion(Woman* concreteElementB)=0; }; //success class Success : public Action { public: virtual void GetManConclusion(Man* concreteElementA) { cout<<"When a man succeeds, there is a great woman behind him"<<endl; } virtual void GetWomanConclusion(Woman* concreteElementB) { cout<<"When a woman succeeds, there is a useless man behind her"<<endl; } }; //fail class Failure : public Action { public: virtual void GetManConclusion(Man* concreteElementA) { cout<<"When a man fails, there is a great woman behind him"<<endl; } virtual void GetWomanConclusion(Woman* concreteElementB) { cout<<"When a woman fails, there is a useless man behind her"<<endl; } }; //Abstract human class Person { public: virtual void Accept(Action* visitor)=0; }; //man class Man : public Person { public: virtual void Accept(Action* visitor) { visitor->GetManConclusion(this); } }; //woman class Woman : public Person { public: virtual void Accept(Action* visitor) { visitor->GetWomanConclusion(this); } }; //Object structure class class ObjectStructure { private: vector<Person*> m_personList; public: void Add(Person* p) { m_personList.push_back(p); } void Display(Action* a) { vector<Person*>::iterator p = m_personList.begin(); while (p!=m_personList.end()) { (*p)->Accept(a); p++; } } }; //client int main() { ObjectStructure * os= new ObjectStructure(); os->Add(new Man()); os->Add(new Woman()); Success* success = new Success(); os->Display(success); Failure* fl = new Failure(); os->Display(fl); return 0; }