讀_設計模式_4(1/4)in4

讀_設計模式_4(1/4)in4

來自專欄一個程序員的路上風景

碼字不易,轉載請註明出處http://xlindo.com

  • 讀《設計模式》
    • 四 行為模式
      • 四點一 Chain of Responsibility 職責鏈
      • 四點二 Command 命令
      • 四點三 Interpreter 解釋器
      • 四點四 Iterator 迭代器
      • 四點五 Mediator 中介者
      • 四點六 Memento 備忘錄
      • 四點七 Observer 觀察者
      • 四點八 State 狀態
      • 四點九 Strategy 策略
      • 四點十 Template Method 模板方法
      • 四點十一 Visitor 訪問者

讀《設計模式》

xlindo 2017年12月18日

四 行為模式

行為模式涉及到演算法和對象間職責的分配。行為模式不僅描述對象或類的模式,還描述它們之間的通信模式。這些模式刻畫了在運行時難以跟蹤的複雜的控制流,它們將你的注意力從控制流轉移到對象間的聯繫方式上來。

四點一 Chain of Responsibility 職責鏈

意圖

使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,知道有一個對象處理它為止。

適用性

  • 有多個對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定;
  • 你想在不明確指定接受者的情況下,向多個對象中的一個提交一個請求;
  • 可處理一個請求的對象集合應被動態指定。

參與者

  • Handler:定義一個處理請求的介面;
  • ConcreteHandler:處理它負責的請求;可訪問它的後繼者;處理或轉發請求;
  • Client:向鏈上的具體處理者對象提交請求。

代碼示例

#include <iostream>using namespace std;class Handle {public: virtual ~Handle() { } virtual void HandleRequest() = 0; void SetSuccessor(Handle *succ) { _succ = succ; } Handle* GetSuccessor()const { return _succ; }protected: Handle() { _succ = nullptr; } Handle(Handle* succ) { _succ = succ; }private: Handle* _succ;};class ConcreteHandleA :public Handle {public: ConcreteHandleA() { } ConcreteHandleA(Handle* succ) :Handle(succ) { } void HandleRequest() { if (this->GetSuccessor() != 0) { cout << "ConcreteHandleA--Successor" << endl; GetSuccessor()->HandleRequest(); } else { cout << "ConcreteHandleA::HandleRequest" << endl; } }};class ConcreteHandleB :public Handle {public: ConcreteHandleB() { } ConcreteHandleB(Handle* succ) :Handle(succ) { } void HandleRequest() { if (this->GetSuccessor() != 0) { cout << "ConcreteHandleB--Successor" << endl; GetSuccessor()->HandleRequest(); } else { cout << "ConcreteHandleB::HandleRequest" << endl; } }};int main() { Handle *h1 = new ConcreteHandleA(); Handle *h2 = new ConcreteHandleB(h1);// or h1->SetSuccessor(h2); h2->HandleRequest(); delete h1; delete h2; return 0;}

四點二 Command 命令

意圖

將一個請求封裝成一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操作。

別名

Action, Transaction

適用性

  • 抽象出待執行的動作以參數化某對象;Command模式是回調機制的一個面向對象的替代品;
  • 在不同的時刻指定、排列和執行請求;
  • 支持取消操作;
  • 支持修改日誌,這樣當系統崩潰時,這些修改可以被重做一遍;
  • 用構建在原語操作上的高層操作構造一個系統:這樣一種結構在支持Transaction的信息系統中很常見。

參與者

  • Command:聲明執行操作的介面;
  • ConcreteCommand:將一個接收者對象綁定於一個動作;調用接收者相應的操作,以實現Execute;
  • Client:創建一個具體命令對象並設定它的接收者;
  • Invoker:要求該命令執行這個請求;
  • Receiver:知道如何實施與執行一個請求相關的操作。

實現

  1. 一個命令對象應達到何種智能程度;
  2. 支持取消和重做;
  3. 避免取消操作過程中的錯誤累積;
  4. 使用C++模板。

代碼示例一

class Command {public: virtual ~Command(); virtual void Execute() = 0;protected: Command();};class OpenCommand : public Command {public: OpenCommand(Application*); virtual void Execute();protected: virtual const char* AskUser();private: Application* _application; char* _response;};OpenCommand::OpenCommand(Application* a){ _application = a;}void OpenCommand::Execute(){ const char* name = AskUser(); if (name != 0) { Document* document = new Document(name); _application->Add(document); document->Open(); }}class PasteCommand : public Command {public: PasteCommand(Document*); virtual void Execute();private: Document* _document;};PasteCommand::PasteCommand(Document* doc){ _document = doc;}void PasteCommand::Execute(){ _document->Paste();}template <class Receiver>class SimpleCommand : public Command {public: typedef void (Receiver::*Action)(); SimpleCommand(Receiver* r, Action a) : _receiver(r) , _action(a) { } virtual void Execute();private: Action _action; Receiver* _receiver;};/*The constructor stores the receiver and the action in the correspondinginstance variables. Execute simply applies the action to the receiver.*/template <class Receiver>void SimpleCommand<Receiver>::Execute(){ (_receiver->*_action)();}/*To create a command that calls Action on an instance of class MyClass, aclient simply writes*/MyClass* receiver = new MyClass;// ...Command* aCommand = new SimpleCommand<MyClass>(receiver, &MyClass::Action);// ...aCommand->Execute();/*Keep in mind that this solution only works for simple commands. Morecomplex commands that keep track of not only their receivers but alsoarguments and/or undo state require a Command subclass.A MacroCommand manages a sequence of subcommands and providesoperations for adding and removing subcommands. No explicit receiver isrequired, because the subcommands already define their receiver.*/class MacroCommand : public Command {public: MacroCommand(); virtual ~MacroCommand(); virtual void Add(Command*); virtual void Remove(Command*); virtual void Execute();private: List<Command*>* _cmds;};/*The key to the MacroCommand is its Execute member function.This traverses all the subcommands and performs Execute on each of them.*/void MacroCommand::Execute(){ ListIterator<Command*> i(_cmds); for (i.First(); !i.IsDone(); i.Next()) { Command* c = i.CurrentItem(); c->Execute(); }}/*Note that should the MacroCommand implement an Unexecute operation,then its subcommands must be unexecuted in reverse order relative toExecutes implementation.Finally, MacroCommand must provide operations to manage its subcommands.The MacroCommand is also responsible for deleting its subcommands.*/void MacroCommand::Add(Command* c){ _cmds->Append(c);}void MacroCommand::Remove(Command* c){ _cmds->Remove(c);}

代碼示例二

#include <iostream>using namespace std;class Reciever {public: void Action() { cout << "Reciever::Action..." << endl; }};class Command {public: virtual ~Command() { } virtual void Excute() = 0;};class ConcreteCommand :public Command {public: ConcreteCommand(Reciever *rev) { _rev = rev; } void Excute() { _rev->Action(); }private: Reciever *_rev;};class Invoker {public: Invoker(Command* cmd) { _cmd = cmd; } void Invoke() { _cmd->Excute(); }private: Command *_cmd;};int main() { Reciever *rev = new Reciever(); Command* cmd = new ConcreteCommand(rev); Invoker *inv = new Invoker(cmd); inv->Invoke(); delete rev; delete cmd; delete inv; return 0;}

四點三 Interpreter 解釋器

意圖

給定一個語言,定義它文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。

參與者

  • AbstractExpression:聲明一個抽象的解釋操作,這個介面被抽象語法樹種所有的節點共享;
  • TerminalExpression:實現文法中終結符相關聯的解釋操作;一個句子中的每個終結符需要該類的一個實例;
  • NonterminalExpression:非終結符表達式;
  • Context:包含解釋器之外的一些全局信息;
  • Client:調用解釋操作;構建表示該文法定義的語言中一個特定的句子的抽象語法樹。

代碼示例一

// 用於求布爾表達式的值得C++程序/*文法如下BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp |( BooleanExp )AndExp ::= BooleanExp and BooleanExpOrExp ::= BooleanExp or BooleanExpNotExp ::= not BooleanExpConstant ::= true | falseVariableExp ::= A | B | ... | X | Y | Z*/class BooleanExp {public: BooleanExp(); virtual ~BooleanExp(); virtual bool Evaluate(Context&) = 0; virtual BooleanExp* Replace(const char*, BooleanExp&) = 0; virtual BooleanExp* Copy() const = 0;};/*The class Context defines a mapping from variables to Boolean values, whichwe represent with the C++ constants true and false. Context has the followinginterface:*/class Context {public: bool Lookup(const char*) const; void Assign(VariableExp*, bool);};//A VariableExp represents a named variable:class VariableExp : public BooleanExp {public: VariableExp(const char*); virtual ~VariableExp(); virtual bool Evaluate(Context&); virtual BooleanExp* Replace(const char*, BooleanExp&); virtual BooleanExp* Copy() const;private: char* _name;};//The constructor takes the variables name as an argument:VariableExp::VariableExp(const char* name){ _name = strdup(name);}//Evaluating a variable returns its value in the current context.bool VariableExp::Evaluate(Context& aContext){ return aContext.Lookup(_name);}//Copying a variable returns a new VariableExp:BooleanExp* VariableExp::Copy() const{ return new VariableExp(_name);}/*To replace a variable with an expression, we check to see if the variable hasthe same name as the one it is passed as an argument:*/BooleanExp* VariableExp::Replace( const char* name, BooleanExp& exp){ if (strcmp(name, _name) == 0) { return exp.Copy(); } else { return new VariableExp(_name); }}//An AndExp represents an expression made by ANDing two Boolean expressions//together.class AndExp : public BooleanExp {public: AndExp(BooleanExp*, BooleanExp*); virtual ~AndExp(); virtual bool Evaluate(Context&); virtual BooleanExp* Replace(const char*, BooleanExp&); virtual BooleanExp* Copy() const;private: BooleanExp* _operand1; BooleanExp* _operand2;};AndExp::AndExp(BooleanExp* op1, BooleanExp* op2){ _operand1 = op1; _operand2 = op2;}//Evaluating an AndExp evaluates its operands and returns the logical "and" of//the results.bool AndExp::Evaluate(Context& aContext){ return _operand1->Evaluate(aContext) && _operand2->Evaluate(aContext);}//An AndExp implements Copy and Replace by making recursive calls on its//operands:BooleanExp* AndExp::Copy() const{ return new AndExp(_operand1->Copy(), _operand2->Copy());}BooleanExp* AndExp::Replace(const char* name, BooleanExp& exp){ return new AndExp( _operand1->Replace(name, exp), _operand2->Replace(name, exp));}/*Now we can define the Boolean expression(true and x) or (y and (not x))and evaluate it for a given assignment of true or false to the variables x andy:*/BooleanExp* expression;Context context;VariableExp* x = new VariableExp("X");VariableExp* y = new VariableExp("Y");expression = new OrExp( new AndExp(new Constant(true), x), new AndExp(y, new NotExp(x)));context.Assign(x, false);context.Assign(y, true);bool result = expression->Evaluate(context);/*The expression evaluates to true for this assignment to x and y. We canevaluate the expression with a different assignment to the variables simplyby changing the context.Finally, we can replace the variable y with a new expression and thenreevaluate it:*/VariableExp* z = new VariableExp("Z");NotExp not_z(z);BooleanExp* replacement = expression->Replace("Y", not_z);context.Assign(z, true);result = replacement->Evaluate(context);

代碼示例二

#include <iostream>#include <string>using namespace std;class Context {};class Expression {public: virtual ~Expression() {} virtual void Interpret(const Context& c) = 0;};class TerminalExpression : public Expression {public: TerminalExpression(const string& statement) { _statement = statement; } void Interpret(const Context& c) { cout << this->_statement << " -- TerminalExpression" << endl; }private: string _statement;};class NonterminalExpression : public Expression {public: NonterminalExpression(Expression* expression, int times) { _expression = expression; _times = times; } void Interpret(const Context& c) { for (int i = 0; i < _times; i++) { _expression->Interpret(c); } }private: Expression* _expression; int _times;};int main(){ Context* c = new Context(); Expression* tp = new TerminalExpression("echo"); Expression* ntp = new NonterminalExpression(tp, 4); ntp->Interpret(*c); delete ntp; delete tp; delete c; return 0;}

四點四 Iterator 迭代器

意圖

提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示。

別名

Cursor 游標

適用性

  • 無需暴露它的內部表示;
  • 支持對聚合對象的多種遍歷;
  • 支持多態迭代。

參與者

  • Iterator:迭代器定義訪問和遍曆元素的介面;
  • ConcreteIterator:實現迭代器介面;對該聚合遍歷時跟蹤當前位置;
  • Aggregate:聚合定義創建相應迭代器對象的介面;
  • ConcreteAggregate:實現介面,返回一個實例。

實現

  1. 誰控制該迭代:外部迭代器:C++不提供匿名函數、閉包;內部迭代器:簡單;
  2. 誰定義遍歷演算法:聚合也可以定義遍歷演算法,游標;
  3. 迭代器健壯程度;
  4. 附加的迭代器操作;
  5. 在C++中使用多態的迭代器:容易忘記刪除,可以使用proxy析構時刪除;
  6. 可有特權訪問:友元;
  7. 空迭代器:用於遍歷樹形結構的聚合。

代碼示例一

// 簡單List類的實現template <class Item>class List {public: List(long size = DEFAULT_LIST_CAPACITY); long Count() const; Item& Get(long index) const; // ...};template <class Item>class Iterator {public: virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() const = 0; virtual Item CurrentItem() const = 0;protected: Iterator();};template <class Item>class ListIterator : public Iterator<Item> {public: ListIterator(const List<Item>* aList); virtual void First(); virtual void Next(); virtual bool IsDone() const; virtual Item CurrentItem() const;private: const List<Item>* _list; long _current;};template <class Item>ListIterator<Item>::ListIterator( const List<Item>* aList) : _list(aList) , _current(0){}template <class Item>void ListIterator<Item>::First(){ _current = 0;}template <class Item>void ListIterator<Item>::Next(){ _current++;}template <class Item>bool ListIterator<Item>::IsDone() const{ return _current >= _list->Count();}Item ListIterator<Item>::CurrentItem() const{ if (IsDone()) { throw IteratorOutOfBounds; } return _list->Get(_current);}// 使用迭代器void PrintEmployees(Iterator<Employee*>& i){ for (i.First(); !i.IsDone(); i.Next()) { i.CurrentItem()->Print(); }}List<Employee*>* employees;// ...ListIterator<Employee*> forward(employees);ReverseListIterator<Employee*> backward(employees);PrintEmployees(forward);PrintEmployees(backward);SkipList<Employee*>* employees;// ...SkipListIterator<Employee*> iterator(employees);PrintEmployees(iterator);template <class Item>class AbstractList {public: virtual Iterator<Item>* CreateIterator() const = 0; // ...};template <class Item>Iterator<Item>* List<Item>::CreateIterator() const{ return new ListIterator<Item>(this);}// we know only that we have an AbstractListAbstractList<Employee*>* employees;// ...Iterator<Employee*>* iterator = employees->CreateIterator();PrintEmployees(*iterator);delete iterator;// 保證迭代器刪除:使用代理template <class Item>class IteratorPtr {public: IteratorPtr(Iterator<Item>* i) : _i(i) { } ~IteratorPtr() { delete _i; } Iterator<Item>* operator->() { return _i; } Iterator<Item>& operator*() { return *_i; }private: // disallow copy and assignment to avoid // multiple deletions of _i: IteratorPtr(const IteratorPtr&); IteratorPtr& operator=(const IteratorPtr&);private: Iterator<Item>* _i;};AbstractList<Employee*>* employees;// ...IteratorPtr<Employee*> iterator(employees->CreateIterator());PrintEmployees(*iterator);

代碼示例二

// IteratorPattern.cpp#include <iostream>#include "Aggregate.h"#include "Iterator.h"using namespace std;int main() { Aggregate* ag = new ConcreteAggreaget(); Iterator *it = new ConcreteIterator(ag, 0); for (; !(it->IsDone()); it->Next()) { cout << it->CurrentItem() << endl; } delete it; delete ag; return 0;}// Iterator.h#pragma once#include "Aggregate.h"class Iterator {public: Iterator(); virtual ~Iterator(); virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() = 0; virtual Object CurrentItem() = 0;};class ConcreteIterator :public Iterator {public: ConcreteIterator(Aggregate *ag, int idx /* = 0 */); void First(); void Next(); bool IsDone(); Object CurrentItem();private: Aggregate* _ag; int _idx;};// Iterator.cpp#include "Iterator.h"Iterator::Iterator() {}Iterator::~Iterator() {}ConcreteIterator::ConcreteIterator(Aggregate *ag, int idx = 0) { _ag = ag; _idx = idx;}Object ConcreteIterator::CurrentItem() { return _ag->GetItem(_idx);}void ConcreteIterator::First() { _idx = 0;}void ConcreteIterator::Next() { if (_idx < _ag->GetSize()) { _idx++; }}bool ConcreteIterator::IsDone() { return (_idx == _ag->GetSize());}// Aggregate.h#pragma onceclass Iterator;typedef int Object;class Aggregate {public: Aggregate(); virtual ~Aggregate(); //virtual Iterator* CreateIterator() = 0; virtual Object GetItem(int idx) = 0; virtual int GetSize() = 0;};class ConcreteAggreaget :public Aggregate {public: enum { SIZE = 3 }; ConcreteAggreaget(); //Iterator* CreateIterator(); Object GetItem(int idx); int GetSize();private: Object _objs[SIZE];};// Aggregate.cpp#include <iostream>using namespace std;#include "Aggregate.h"#include "Iterator.h"Aggregate::Aggregate() {}Aggregate::~Aggregate() {}ConcreteAggreaget::ConcreteAggreaget() { for (int i = 0; i < SIZE; i++) { _objs[i] = i; }}//Iterator* ConcreteAggreaget::CreateIterator() {// return new ConcreteIterator(this);//}Object ConcreteAggreaget::GetItem(int idx) { if (idx < this->GetSize()) { return _objs[idx]; } else { return -1; }}int ConcreteAggreaget::GetSize() { return SIZE;}

推薦閱讀:

TAG:設計模式 | 編程語言 | 軟體工程 |