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

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

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

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

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

讀《設計模式》

xlindo 2017年12月18日

四點十一 Visitor 訪問者

意圖

表示一個作用於某對象結構中的各元素的操作。

適用性

  • 一個對象結構包括很多類對象,它們有不同的介面,而你相對這些對象實施一些依賴與其具體類的操作;
  • 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而你想避免「污染」;
  • 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。

參與者

  • Visitor:為該對象結構中ConcreteElement的每一個類聲明一個Visit操作,以確定正在被訪問元素的類;
  • ConcreteVisitor:實現每個由Visitor聲明的操作;
  • Element:定義一個Accept操作,它以一個訪問者為參數;
  • ConcreteElement:實現Accept操作;
  • ObjectStructure:能枚舉它的元素;可以提供一個高層介面供元素訪問。

代碼示例一

class Equipment {public: virtual ~Equipment(); const char* Name() { return _name; } virtual Watt Power(); virtual Currency NetPrice(); virtual Currency DiscountPrice(); virtual void Accept(EquipmentVisitor&);protected: Equipment(const char*);private: const char* _name;};//The Equipment operations return the attributes of a piece of equipment,//such as its power consumption and cost. Subclasses redefine these operations//appropriately for specific types of equipment (e.g., a chassis, drives, and//planar boards).//The abstract class for all visitors of equipment has a virtual function for each//subclass of equipment, as shown next. All of the virtual functions do nothing//by default.class EquipmentVisitor {public: virtual ~EquipmentVisitor(); virtual void VisitFloppyDisk(FloppyDisk*); virtual void VisitCard(Card*); virtual void VisitChassis(Chassis*); virtual void VisitBus(Bus*); // and so on for other concrete subclasses of Equipmentprotected: EquipmentVisitor();};//Equipment subclasses define Accept in basically the same way: It calls the//EquipmentVisitor operation that corresponds to the class that received the//Accept request, like this:void FloppyDisk::Accept(EquipmentVisitor& visitor){ visitor.VisitFloppyDisk(this);}//Equipment that contains other equipment (in particular, subclasses of//CompositeEquipment in the Composite pattern) implements Accept by//iterating over its children and calling Accept on each of them. Then it calls//the Visit operation as usual. For example, Chassis::Accept could traverse all//the parts in the chassis as follows:void Chassis::Accept(EquipmentVisitor& visitor){ for ( ListIterator i(_parts); !i.IsDone(); i.Next()) { i.CurrentItem()->Accept(visitor); } visitor.VisitChassis(this);}//Subclasses of EquipmentVisitor define particular algorithms over the//equipment structure. The PricingVisitor computes the cost of the equipment//structure. It computes the net price of all simple equipment (e.g., floppies)//and the discount price of all composite equipment (e.g., chassis and buses).class PricingVisitor : public EquipmentVisitor {public: PricingVisitor(); Currency& GetTotalPrice(); virtual void VisitFloppyDisk(FloppyDisk*); virtual void VisitCard(Card*); virtual void VisitChassis(Chassis*); virtual void VisitBus(Bus*); // ...private: Currency _total;};void PricingVisitor::VisitFloppyDisk(FloppyDisk* e){ _total += e->NetPrice();}void PricingVisitor::VisitChassis(Chassis* e){ _total += e->DiscountPrice();}//PricingVisitor will compute the total cost of all nodes in the equipment//structure. Note that PricingVisitor chooses the appropriate pricing policy for//a class of equipment by dispatching to the corresponding member function.//Whats more, we can change the pricing policy of an equipment structure just//by changing the PricingVisitor class.//We can define a visitor for computing inventory like this:class InventoryVisitor : public EquipmentVisitor {public: InventoryVisitor(); Inventory& GetInventory(); virtual void VisitFloppyDisk(FloppyDisk*); virtual void VisitCard(Card*); virtual void VisitChassis(Chassis*); virtual void VisitBus(Bus*); // ...private: Inventory _inventory;};//The InventoryVisitor accumulates the totals for each type of equipment in//the object structure. InventoryVisitor uses an Inventory class that defines an//interface for adding equipment (which we wont bother defining here).void InventoryVisitor::VisitFloppyDisk(FloppyDisk* e){ _inventory.Accumulate(e);}void InventoryVisitor::VisitChassis(Chassis* e){ _inventory.Accumulate(e);}//Heres how we can use an InventoryVisitor on an equipment structure:Equipment* component;InventoryVisitor visitor;component->Accept(visitor);cout << "Inventory " << component->Name() << visitor.GetInventory();

代碼示例二

#include <iostream>#include "Element.h"#include "Visitor.h"using namespace std;int main() { Visitor *vis = new ConcreteVisitorA(); Element *elm = new ConcreteElementA(); elm->Accept(vis); delete elm; delete vis; return 0;}// visitor.h#pragma once#include "Element.h"class Element;class Visitor {public: virtual ~Visitor(); virtual void VisitConcreteElementA(Element* elm) = 0; virtual void VisitConcreteElementB(Element* elm) = 0;protected: Visitor();};class ConcreteVisitorA :public Visitor {public: void VisitConcreteElementA(Element* elm); void VisitConcreteElementB(Element* elm);};class ConcreteVisitorB :public Visitor {public: void VisitConcreteElementA(Element* elm); void VisitConcreteElementB(Element* elm);};// visitor.cpp#include "Visitor.h"#include <iostream>using namespace std;Visitor::Visitor() {}Visitor::~Visitor() {}void ConcreteVisitorA::VisitConcreteElementA(Element* elm) { cout << "i will visit ConcreteElementA..." << endl;}void ConcreteVisitorA::VisitConcreteElementB(Element* elm) { cout << "i will visit ConcreteElementB..." << endl;}void ConcreteVisitorB::VisitConcreteElementA(Element* elm) { cout << "i will visit ConcreteElementA..." << endl;}void ConcreteVisitorB::VisitConcreteElementB(Element* elm) { cout << "i will visit ConcreteElementB..." << endl;}//Element.h#pragma once#include "Visitor.h"class Visitor;class Element {public: Element(); virtual ~Element(); virtual void Accept(Visitor* vis) = 0;};class ConcreteElementA :public Element {public: void Accept(Visitor* vis);};class ConcreteElementB :public Element {public: void Accept(Visitor* vis);};//Element.cpp#include "Element.h"#include <iostream>using namespace std;Element::Element() {}Element::~Element() {}void ConcreteElementA::Accept(Visitor* vis) { vis->VisitConcreteElementA(this); cout << "visiting ConcreteElementA..." << endl;}void ConcreteElementB::Accept(Visitor* vis) { vis->VisitConcreteElementB(this); cout << "visiting ConcreteElementA..." << endl;}

推薦閱讀:

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