二十三、Visitor(访问者)
情景举例:
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
代码示例:
/* 被访问类的父类,注意其中虚拟函数Accept是提供给访问者的接口
*/
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;
};
/* 访问者的父类,多个虚拟函数让子类可以自定义其行为(仅行为)
*/
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 Equipment
protected:
EquipmentVisitor();
};
/* 下面几个是被访问者的具体类
*/
class FloppyDisk : public Equipment {
public:
virtual void Accept(EquipmentVisitor&);
};
/* accept里调用了访问者的某个虚拟函数
*/
void FloppyDisk::Accept (EquipmentVisitor& visitor) {
visitor.VisitFloppyDisk(this);
}
/* 另一个具体类的例子
*/
class CompositeEquipment : public Equipment {
public:
virtual void Accept(EquipmentVisitor&);
};
class Chassis : public CompositeEquipment {
public:
virtual void Accept(EquipmentVisitor&);
List<Equipment*>* _parts;
};
/*
*/
void Chassis::Accept (EquipmentVisitor& visitor) {
for (
ListIterator<Equipment*> i(_parts);
!i.IsDone();
i.Next()
) {
i.CurrentItem()->Accept(visitor);
}
visitor.VisitChassis(this);
}
/* 访问者类的具体类,定义了父类的虚拟函数的实现
*/
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();
}
/* 另一个具体类
*/
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;
};
/*
*/
void InventoryVisitor::VisitFloppyDisk (FloppyDisk* e) {
_inventory.Accumulate(e);
}
/*
*/
void InventoryVisitor::VisitChassis (Chassis* e) {
_inventory.Accumulate(e);
}
/* 主程序中展示了使用的方法
*/
ostream& operator<<(ostream&, const Inventory&);
void dummy() {
/*
*/
Equipment* component;
InventoryVisitor visitor;
component->Accept(visitor);
cout << "Inventory "
<< component->Name()
<< visitor.GetInventory();
/*
*/
}
个人理解:
简单来讲,visitor模式是一个双分派的实现方法,即根据两种类型来实现多态。C++中只能由一种类型来实现多态,但用visitor模式就可以做到。在Meyer的Effictive C++中对这种方法有更具体的介绍。这种模式是在于被访问类不方便修改或者无法访问代码的时候适用的(但被访问类至少要提供给访问类一个接口,如accept)