U E D R , A S I H C RSS

Gof/Visitor


1. Visitor

1.1. Intent

object structure ˜ element๋“ค— ˆ˜–‰๋  operation „ ‘œ˜„•œ‹ค. Visitor๋Š” •ด๋‹น operationˆ˜–‰๋˜๋Š” element˜ class— ๋Œ€•œ ๋ณ€™” —†ƒˆ๋กœšด operation„  •˜•  ˆ˜ žˆ๋„๋ก •ค€๋‹ค.

1.2. Motivation

ปดŒŒผ๋Ÿฌฐ€ abstact syntax tree๋กœ ”„๋กœธ๋žจ„ ‘œ˜„•œ‹  •˜ž. ปดŒŒผ๋Ÿฌ๋Š” ๋ชจ๋“  ๋ณ€ˆ˜๋“ค •˜ฐ€ ๋˜–ดžˆ๋Š” ง€๋ฅผ ฒ€‚ฌ•˜๋Š” ฒƒณผ ฐ™€ ' • ˜๋ฏธ' ๋ถ„„„ œ„•ด abstract syntax tree— ๋Œ€•ด operation„ ˆ˜–‰•  •„š”ฐ€ žˆ„ ฒƒด๋‹ค. ปดŒŒผ๋Ÿฌ๋Š” ๋˜•œ code ๋ณ€™˜„ •  •„š”ฐ€ žˆ๋‹ค. ๋˜•œ ปดŒŒผ๋Ÿฌ๋Š” type-checking, code optimization, flow analysis ™€ •ด๋‹น ๋ณ€ˆ˜ฐ€ šฉ๋˜ธฐ  „ „ –ธ๋˜—ˆ๋Š”ง€ ๋“ฑ˜ —ฌ๋ถ€๋ฅผ ฒ€‚ฌ•˜ธฐ œ„•„œ •ด๋‹น operations๋“ค„ ˆ˜–‰•  •„š”ฐ€ žˆ๋‹ค. ๋” ๋‚˜•„ฐ€ šฐ๋ฆฌ๋Š” pretty-printing, program restructuring, code instrumentation, ธ๋ฆฌ  ”„๋กœธ๋žจ˜‹–‘•œ ธฐค€๋“ค— ๋Œ€•œ „‚ฐ„ •˜ธฐ œ„•ด abstract syntax tree๋ฅผ šฉ•  ฒƒด๋‹ค.

ด๋Ÿฌ•œ operations๋“ค˜ ๋Œ€๋ถ€๋ถ„๋“ค€ variable๋“คด๋‚˜ arithmetic expression๋“ค„ ‘œ˜„•˜๋Š” node๋“คณผ ๋‹ค๋ฅดฒŒ assignment statement๋“ค„ ‘œ˜„•˜๋Š” node๋ฅผ ธ‰•  •„š”ฐ€ žˆ๋‹ค. ๋”ฐ๋„œ, ฐฐ assignment statement ๋ฅผ œ„•œ ด๋ž˜Šค™€, variable —  ‘•˜ธฐ œ„•œ ด๋ž˜Šค, arithmetic expression„ œ„•œ ด๋ž˜Šค๋“คžˆ–ด••  ฒƒด๋‹ค. ด๋Ÿฌ•œ node class๋“ค€ ปดŒŒผ ๋  –ธ–ด— ˜กด ด๋ฉฐ, ๋˜•œ ฃผ–ด„ –ธ–ด๋ฅผ œ„•ด ๋ฐ”๋€Œง€ •Š๋Š”๋‹ค.


ด ๋‹–ดธ๋žจ€ Node class „ธตตฌกฐ˜ ผ๋ถ€๋ถ„„ ๋ณด—ฌค€๋‹ค. —ฌธฐ„œ˜ ๋ฌธ œ๋Š” ๋‹–‘•œ node class๋“ค— žˆ๋Š” ด๋Ÿฌ•œ operation๋“ค˜ ๋ถ„‚ฐ€ ‹œŠค…œœผ๋กœ •˜—ฌธˆ ••˜ธฐ –ด๋  , œ ง€•˜ฑฐ๋‚˜ ฝ”๋“œ๋ฅผ ๋ฐ”พธธฐ ž˜๋“คฒŒ •œ‹ค. Node — type-checking ฝ”๋“œฐ€ pretty-printing code๋‚˜ flow analysis code๋“คณผ „ž—ฌ žˆ๋Š” ฒƒ€ ˜ผ๋ž€Šค๋Ÿฝ๋‹ค. ฒŒ๋‹ฐ€ ƒˆ๋กœšด operation„ ถ”ฐ€•˜ธฐ œ„•„œ๋Š” ผ๋ฐ˜ œผ๋กœ ด๋ž˜Šค๋“ค„ žฌปดŒŒ•••œ‹ค. ๋งŒฐฐ˜ ƒˆ operationด ๋…๋ฆฝ œผ๋กœ ถ”ฐ€๋  ˆ˜ žˆ , ด node class๋“คด operation๋“ค— ๋Œ€•ด ๋…๋ฆฝ ด๋ผ๋ฉด ๋”šฑ ‹„ ฒƒด๋‹ค.

šฐ๋ฆฌ๋Š” ฐฐ˜ ด๋ž˜Šค๋“ค๋กœ๋ถ€„ด€๋ จ๋œ operation๋“ค„ Œจ‚ค•™” •˜ , traverse ๋  (tree ˜ ฐ node๋“ค„ ด๋™) abstract syntax tree˜ element๋“ค—ฒŒ ž๋กœ„˜ฒจ„ ˆ˜ žˆ๋‹ค. ด๋ฅผ visitor๋  •œ‹ค. elementฐ€ visitor๋ฅผ 'accepts' • •Œ element๋Š” element˜ ด๋ž˜Šค๋ฅผ ฝ”๋”ฉ•  visitor—ฒŒ request๋ฅผ ๋ณด๋‚ธ๋‹ค. ด request ๋˜•œ •ด๋‹น element๋ฅผ ž๋กœ ฌ••˜  žˆ๋‹ค. ธ๋Ÿฌ๋ฉด visitor๋Š” •ด๋‹น element— ๋Œ€•œ operation„ ˆ˜–‰•  ฒƒด๋‹ค.

˜ˆ๋ฅผ๋“ ‹ค๋ฉด, visitor๋ฅผ šฉ•˜ง€ •Š๋Š” ปดŒŒผ๋Ÿฌ๋Š” ปดŒŒผ๋Ÿฌ˜ abstact syntax tree˜ TypeCheck operation„ ˜œ•œผ๋กœ„œ type-check „ ˆ˜–‰•  ฒƒด๋‹ค. ฐฐ˜ node๋“ค€ node๋“คฐ€ง€  žˆ๋Š” TypeCheck๋ฅผ ˜œ•œผ๋กœจ TypeCheck๋ฅผ ตฌ˜„•  ฒƒด๋‹ค. (•ž˜ class diagram ฐธกฐ). ๋งŒผ visitor๋ฅผ šฉ•œ‹ค๋ฉด, TypeCheckingVisior ฒด๋ฅผ ๋งŒ๋“  ๋’ค, TypeCheckingVisitor ฒด๋ฅผ ž๋กœ„˜ฒจฃผ๋ฉด„œ abstract syntax tree˜ Accept operation„ ˜œ•  ฒƒด๋‹ค. ฐฐ˜ node๋“ค€ visitor๋ฅผ ๋„๋กœ ˜œ•œผ๋กœจ Accept๋ฅผ ตฌ˜„•  ฒƒด๋‹ค (˜ˆ๋ฅผ ๋“ค–ด, assignment node˜ ฒฝšฐ visitor˜ VisitAssignment operation„ ˜œ•  ฒƒ , varible reference๋Š” VisitVaribleReference๋ฅผ ˜œ•  ฒƒด๋‹ค.) AssignmentNode ด๋ž˜Šค˜ TypeCheck operation€  œ TypeCheckingVisitor˜ VisitAssignment operationœผ๋กœ ๋Œ€ฒด๋  ฒƒด๋‹ค.

type-checking ˜ ธฐ๋Šฅ„„˜–ด ผ๋ฐ˜ ธ visitor๋ฅผ ๋งŒ๋“คธฐ œ„•„œ๋Š” abstract syntax tree˜ ๋ชจ๋“  visitor๋“ค„ œ„•œ abstract parent classNodeVisitorฐ€ •„š”•˜‹ค. NodeVisitor๋Š” ฐ node class๋“ค— žˆ๋Š” operation๋“ค„  •˜•••œ‹ค. •ด๋‹”„๋กœธ๋žจ˜ ธฐค€ ๋“ฑ„ „‚ฐ•˜ธฐ ›•˜๋Š” application€ node class — application-specific•œ ฝ”๋“œ๋ฅผ ถ”ฐ€•  •„š” —†ด, ธ๋ƒฅ NodeVisitor— ๋Œ€•œ ƒˆ๋กœšด subclass๋ฅผ  •˜•˜๋ฉด ๋œ‹ค. VisitorPattern€ •ด๋‹น Visitor ™€ —ฐด€๋œ ๋ถ€๋ถ„—„œ ปดŒŒผ๋œ ตฌ๋ฌธ๋“ค„ œ„•œ operation๋“ค„ บกА™”•œ‹ค.



VisitorPatternœผ๋กœ, œ๋ฐœž๋Š” ๋‘œ˜ ด๋ž˜Šค „ธต„  •˜•œ‹ค. •˜๋‚˜๋Š” operationˆ˜–‰๋  element— ๋Œ€•œ „ธต  (Node hierarchy), •˜๋‚˜๋Š” element— ๋Œ€•œ operation๋“ค„  •˜•˜๋Š” visitor๋“คด๋‹ค. (NodeVisitor hierarchy). œ๋ฐœž๋Š” visitor hierarchy — ƒˆ๋กœšด subclass๋ฅผ ถ”ฐ€•œผ๋กœ„œ ƒˆ operation„ ๋งŒ๋“ค ˆ˜ žˆ๋‹ค.

1.3. Applicability

VisitorPattern€ ๋‹Œณผ ฐ™€ฒฝšฐ— šฉ•œ‹ค.


1.5. Participants

  • Visitor (NodeVisitor)
    - declares a Visit operations 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 class of the element being visited. Then the visitor can access the element directly through its particular interface.
  • ConcreteVisitor (TypeCheckingVisitor)
    - implements each operation 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 result during the traversal of the structure.
  • Element (Node)
    - defines an Accept operation that takes a visitor as an argument.
  • ConcreteElement (AssignmentNode, VariableRefNode)
    - implements an Accept operation that takes a visitor as an argument.
  • ObjectStructure (Program)
    - can enumerate its elements.

    - may provide a high-level interface to allow the visitor to visit its elements.

    - may either be a composite (See CompositePattern) or a collection such as a list or a set.


1.6. Collaborations

1.7. Consequences

template <class Item>
class Iterator {
	// ...
	Item CurrentItem () const;
};

class Visitor {
public:
	// ...
	void VisitMyType (MyType*);
	void VisitYourType (YourType*);
};

1.8. Implementation

class Visitor {
public:
	virtual void VisitElementA (ElementA*);
	virtual void VisitElementB (ElementB*);

	// and so on for other concrete elements
protected:
	Visitor ();
};

class Element {
public:
	virtual ~Element ();
	virtual void Accept (Visitor&) = 0;
protected:
	Element ();
};

class ElementA : public Element {
public:
	ElementA ();
	virtual void Accept (Visitor& v) { v.VisitElementA (this); }
};

class ElementB : public Element {
public:
	ElementB ();
	virtual void Accept (Visitor& v) { v.VisitElementB (this); }
};

class CompositeElement : public Element {
public:
	virtual void Accept (Visitor&);
private:
	List<Element*>* _children;
};

void CompositeElement::Accept (Visitor& v) {
	ListIterator<Element*> i (_children);

	for (i.First (); !i.IsDone(); i.Next ()) {
		i.CurrentItem ()->Accept (v);
	}
	v.VisitCompositeElement (this);
}

1.9. Sample Code


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 VisitrChassis (Chassis*);
	virtual void VisitBus (Bus*);

	// and so on for other concrete subclasses of Equipment
protected:
	EquipmentVisitor ();
};

void FloppyDisk::Accept (EquipmentVisitor& visitor) {
	visitor.VisitFloppyDisk (this);
}

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->NextPrice ();
}

void PricingVisitor::VisitChassis (Chassis* e) {
	_total += e->DiscountPrice ();
}

class InventoryVisitoy : 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);
}

Equipment* component;
InventoryVisitor visitor;

component->Accept (visitor);
cout << "Inventory "
	<< componet->Name ()
	<< visitor.GetInventory ();


accept: aVisitor
	^ aVisitor visitSequence : self

visitSequence: sequenceExp
	inputState := sequenceExp expression1 accept: self.
	^ sequenceExp expression2 accept: self.

visitRepeat : repeatExp
	| finalState |
	finalState := inputState copy.
	[inputState isEmpty]
		whileFalse:
		[inputState := repeatExp repetition accept: self.
		finalState addAll: inputState].
	^ finalState

visitAlternation: alternateExp
	| finalState originalState |
	originalState := inputState.
	finalState := alternateExp alternative1 accept: self.
	inputState := originalState.
	finalState addAll: (alternateExp alternative2 accept: self).
	^ finalState

visitLiteral: literalExp
	| finalState tStream |
	finalState := Set new.
	inputState
		do:
			[:stream | tStream := stream copy.
				(tStream nextAvailable:
					literalExp components size
				) = literalExp components
					ifTrue: [finalState add: tStream]
			].
	^ finalState

1.10. Known Uses


Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:19
Processing time 0.1296 sec