DesignPatterns_Visitor

////////////////////////////////////////////////////////////////////////////////////
// Visitor pattern
// - 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.
//
// For example:
// - 爸爸(ConcreteVisitor1)帶着兒子(ConcreteVisitor2)去書店(ConcreteElementA)買書,
//    爸爸買了一套《平凡的世界》(ConcreteVisitor1::VisitConcreteElementA),
//    兒子買了一本《安徒生童話集》(ConcreteVisitor2::VisitConcreteElementA)。
//    從書店出來,兒子說渴了,爸爸便帶着兒子去附近的超市(ConcreteElementB),
//    父親買了一瓶礦泉水(ConcreteVisitor1::VisitConcreteElementB),
//    兒子買了一瓶爽歪歪(ConcreteVisitor2::VisitConcreteElementB)。
//    如果是爸爸媽媽兒子三人出門,在上述的基礎上,增加一個ConcreteVisitor3(媽媽),再分別實現
//    ConcreteVisitor3::VisitConcreteElementA(媽媽買了一本《一週一樣拿手菜》)
//    ConcreteVisitor3::VisitConcreteElementB(媽媽買了一杯《珍珠奶茶》)即可。
//
// Author     : ZAsia
// Date       : 15/05/20
// Warning    : In practice, declaration and implementation should
//              be separated(.h and .cpp).
/////////////////////////////////////////////////////////////////////////////////////
#include 
#include 
using namespace std;

class ConcreteElementA;
class ConcreteElementB;

// Visitor
// - declares a Visit operation for each class of ConcreteElement in the object
//   structure. The operation's name and signature identifies the class that sends
//   the Visit request to the visitor. That lets the visitor determine the concrete
//   the concrete class of the element being visited. Then the visitor can access the
//   element directly through its particular interface.
class Visitor
{
public:
	virtual void VisitConcreteElementA(ConcreteElementA *concreteElementA) = 0;
	virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB) = 0;
};

// ConcreteVisitor
// - implements each oepration declared by Visitor. Each operation implements 
//   a fragment of the algorithm defined for the corresponding class of object
//   in the structure. ConcreteVisitor provides the context for the algorithm
//   and stores its local state. This state often accumulates results during
//   the traversal of the structure.
class ConcreteVisitor1 : public Visitor
{
public:
	virtual void VisitConcreteElementA(ConcreteElementA *concreteElementA)
	{
		cout << "ConcreteVisitor1::VisitConcreteElementA..." << endl;
	}

	virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB)
	{
		cout << "ConcreteVisitor1::VisitConcreteElementB..." << endl;
	}
};

class ConcreteVisitor2 : public Visitor
{
public:
	virtual void VisitConcreteElementA(ConcreteElementA *concreteElementA)
	{
		cout << "ConcreteVisitor2::VisitConcreteElementA..." << endl;
	}

	virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB)
	{
		cout << "ConcreteVisitor2::VisitConcreteElementB..." << endl;
	}
};

// Element
// - defines an Accept operation that takes a visitor as an argument.
class Element
{
public:
	virtual void Accept(Visitor *visitor) = 0;
};

// ConcreteElement
// - implements an Accept operation that takes a visitor as an argument.
class ConcreteElementA : public Element
{
public:
	virtual void Accept(Visitor *visitor)
	{
		visitor->VisitConcreteElementA(this);
	}
};

class ConcreteElementB : public Element
{
public:
	virtual void Accept(Visitor *visitor)
	{
		visitor->VisitConcreteElementB(this);
	}
};

// ObjectStructure
// - can enumerate its elements.
// - may provide a high-level interface to allow the visitor to visit its elements.
// - may either be a composite or a collection such as a list or a set.
class ObjectStructure
{
public:
	void Accept(Visitor *visitor)
	{
		for (list::iterator iter = _elements.begin();
			iter != _elements.end(); ++iter)
		{
			(*iter)->Accept(visitor);
		}
	}

	void Attach(Element *element)
	{
		_elements.push_back(element);
	}

	void Detach(Element *element)
	{
		_elements.remove(element);
	}

private:
	list _elements;
};

// Collaborations
// - A client that uses the Visitor pattern must create a ConcreteVisitor object and
//   than traverse the object structure, visiting each element with the visitor.
// - When an element is visited, it calls the Visitor operation that corresponds to 
//   its class. The element supplies itself as an argument to this operaton to let the
//   visitor access its state, if neccessary.
int main()
{
	ConcreteElementA *pConcreteElementA = new ConcreteElementA();
	ConcreteElementB *pConcreteElementB = new ConcreteElementB();

	ObjectStructure *pObjectStructure = new ObjectStructure();
	pObjectStructure->Attach(pConcreteElementA);
	pObjectStructure->Attach(pConcreteElementB);

	ConcreteVisitor1 *pConcreteVisitor1 = new ConcreteVisitor1();
	pObjectStructure->Accept(pConcreteVisitor1);

	pObjectStructure->Detach(pConcreteElementB);

	ConcreteVisitor2 *pConcreteVisitor2 = new ConcreteVisitor2();
	pObjectStructure->Accept(pConcreteVisitor2);

	delete pConcreteElementA;
	delete pConcreteElementB;
	delete pObjectStructure;
	delete pConcreteVisitor1;
	delete pConcreteVisitor2;

	return 0;
}

////////////////////////////////////////////////////////////////////////////
// 1.Visitor makes adding new operations easy. You can define a new operation
//   over an object structure simply by adding a new visitor.
// 2.A visitor gathers related operations and separates unrelated ones. Related
//   behavior isn't spread over the classes defining the object structure; it's 
//   localized in a visitor. Unrelated sets of behavior are partitioned in their
//   own visitor subclasses. That simplies both the classes defining the element
//   and the algorithms defined in the visitors. Any algorithm-specific data 
//   structures can be hidden in the visitor.
// 3.Add new ConcreteElement classes is hard. Each new ConcreteElement gives rise
//   to a new abstract operation on Visitor and a corresponding implementation in
//   every ConcreteVisitor class.
// 4.Each Visit operation on the Visitor declares its argument to be a particular
//   ConcreteElement, allowing the Visitor to access the interface fo the ConcreteElement
//   directly. ConcreteVisitor classes override each Visit operation to implement
//   visitor-specific behavior for the corresponding ConcreteElement class.
// 5.Double dispatch. The operation that gets executed depends on both the type of
//   Visitor and the type of Element it visits. Instead of binding operations 
//   statically into the Element interface, you can consolidate the operations in a
//   Visitor and use Accept to do the binding at run-time. Extending the Element
//   interface amounts to defining one Visitor subclass rather than many new Element
//   subclasses.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章