namespaceRefactoringGuru.DesignPatterns.Visitor.Conceptual { // The Component interface declares an `accept` method that should take the // base visitor interface as an argument. publicinterfaceIComponent { voidAccept(IVisitor visitor); }
// Each Concrete Component must implement the `Accept` method in such a way // that it calls the visitor's method corresponding to the component's // class. publicclassConcreteComponentA : IComponent { // Note that we're calling `VisitConcreteComponentA`, which matches the // current class name. This way we let the visitor know the class of the // component it works with. publicvoidAccept(IVisitor visitor) { visitor.VisitConcreteComponentA(this); }
// Concrete Components may have special methods that don't exist in // their base class or interface. The Visitor is still able to use these // methods since it's aware of the component's concrete class. publicstringExclusiveMethodOfConcreteComponentA() { return"A"; } }
// The Visitor Interface declares a set of visiting methods that correspond // to component classes. The signature of a visiting method allows the // visitor to identify the exact class of the component that it's dealing // with. publicinterfaceIVisitor { voidVisitConcreteComponentA(ConcreteComponentA element);
// Concrete Visitors implement several versions of the same algorithm, which // can work with all concrete component classes. // // You can experience the biggest benefit of the Visitor pattern when using // it with a complex object structure, such as a Composite tree. In this // case, it might be helpful to store some intermediate state of the // algorithm while executing visitor's methods over various objects of the // structure. classConcreteVisitor1 : IVisitor { publicvoidVisitConcreteComponentA(ConcreteComponentA element) { Console.WriteLine(element.ExclusiveMethodOfConcreteComponentA() + " + ConcreteVisitor1"); }
publicclassClient { // The client code can run visitor operations over any set of elements // without figuring out their concrete classes. The accept operation // directs a call to the appropriate operation in the visitor object. publicstaticvoidClientCode(List<IComponent> components, IVisitor visitor) { foreach (var component in components) { component.Accept(visitor); } } }
classProgram { staticvoidMain(string[] args) { List<IComponent> components = new List<IComponent> { new ConcreteComponentA(), new ConcreteComponentB() };
Console.WriteLine("The client code works with all visitors via the base Visitor interface:"); var visitor1 = new ConcreteVisitor1(); Client.ClientCode(components,visitor1);
Console.WriteLine();
Console.WriteLine("It allows the same client code to work with different types of visitors:"); var visitor2 = new ConcreteVisitor2(); Client.ClientCode(components, visitor2); } } }
Output.txt: 执行结果
1 2 3 4 5 6 7
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1
It allows the same client code to work with different types of visitors: A + ConcreteVisitor2 B + ConcreteVisitor2
/** * The Visitor Interface declares a set of visiting methods that correspond to * component classes. The signature of a visiting method allows the visitor to * identify the exact class of the component that it's dealing with. */ classConcreteComponentA; classConcreteComponentB;
/** * Each Concrete Component must implement the `Accept` method in such a way that * it calls the visitor's method corresponding to the component's class. */ classConcreteComponentA : public Component { /** * Note that we're calling `visitConcreteComponentA`, which matches the * current class name. This way we let the visitor know the class of the * component it works with. */ public: voidAccept(Visitor *visitor)constoverride{ visitor->VisitConcreteComponentA(this); } /** * Concrete Components may have special methods that don't exist in their base * class or interface. The Visitor is still able to use these methods since * it's aware of the component's concrete class. */ std::string ExclusiveMethodOfConcreteComponentA()const{ return"A"; } };
/** * Concrete Visitors implement several versions of the same algorithm, which can * work with all concrete component classes. * * You can experience the biggest benefit of the Visitor pattern when using it * with a complex object structure, such as a Composite tree. In this case, it * might be helpful to store some intermediate state of the algorithm while * executing visitor's methods over various objects of the structure. */ classConcreteVisitor1 : public Visitor { public: voidVisitConcreteComponentA(const ConcreteComponentA *element)constoverride{ std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor1\n"; }
classConcreteVisitor2 : public Visitor { public: voidVisitConcreteComponentA(const ConcreteComponentA *element)constoverride{ std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor2\n"; } voidVisitConcreteComponentB(const ConcreteComponentB *element)constoverride{ std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor2\n"; } }; /** * The client code can run visitor operations over any set of elements without * figuring out their concrete classes. The accept operation directs a call to * the appropriate operation in the visitor object. */ voidClientCode(std::array<const Component *, 2> components, Visitor *visitor){ // ... for (const Component *comp : components) { comp->Accept(visitor); } // ... }
intmain(){ std::array<const Component *, 2> components = {new ConcreteComponentA, new ConcreteComponentB}; std::cout << "The client code works with all visitors via the base Visitor interface:\n"; ConcreteVisitor1 *visitor1 = new ConcreteVisitor1; ClientCode(components, visitor1); std::cout << "\n"; std::cout << "It allows the same client code to work with different types of visitors:\n"; ConcreteVisitor2 *visitor2 = new ConcreteVisitor2; ClientCode(components, visitor2);
/** * The Component interface declares an `accept` method that should take the base * visitor interface as an argument. */ interfaceComponent { publicfunctionaccept(Visitor $visitor): void; }
/** * Each Concrete Component must implement the `accept` method in such a way that * it calls the visitor's method corresponding to the component's class. */ classConcreteComponentAimplementsComponent { /** * Note that we're calling `visitConcreteComponentA`, which matches the * current class name. This way we let the visitor know the class of the * component it works with. */ publicfunctionaccept(Visitor $visitor): void { $visitor->visitConcreteComponentA($this); }
/** * Concrete Components may have special methods that don't exist in their * base class or interface. The Visitor is still able to use these methods * since it's aware of the component's concrete class. */ publicfunctionexclusiveMethodOfConcreteComponentA(): string { return"A"; } }
/** * The Visitor Interface declares a set of visiting methods that correspond to * component classes. The signature of a visiting method allows the visitor to * identify the exact class of the component that it's dealing with. */ interfaceVisitor { publicfunctionvisitConcreteComponentA(ConcreteComponentA $element): void;
/** * Concrete Visitors implement several versions of the same algorithm, which can * work with all concrete component classes. * * You can experience the biggest benefit of the Visitor pattern when using it * with a complex object structure, such as a Composite tree. In this case, it * might be helpful to store some intermediate state of the algorithm while * executing visitor's methods over various objects of the structure. */ classConcreteVisitor1implementsVisitor { publicfunctionvisitConcreteComponentA(ConcreteComponentA $element): void { echo$element->exclusiveMethodOfConcreteComponentA() . " + ConcreteVisitor1\n"; }
/** * The client code can run visitor operations over any set of elements without * figuring out their concrete classes. The accept operation directs a call to * the appropriate operation in the visitor object. */ functionclientCode(array$components, Visitor $visitor) { // ... foreach ($componentsas$component) { $component->accept($visitor); } // ... }
echo"The client code works with all visitors via the base Visitor interface:\n"; $visitor1 = newConcreteVisitor1(); clientCode($components, $visitor1); echo"\n";
echo"It allows the same client code to work with different types of visitors:\n"; $visitor2 = newConcreteVisitor2(); clientCode($components, $visitor2);
Output.txt: 执行结果
1 2 3 4 5 6 7
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1
It allows the same client code to work with different types of visitors: A + ConcreteVisitor1 B + ConcreteVisitor2
/** * The Component interface declares a method of accepting visitor objects. * * In this method, a Concrete Component must call a specific Visitor's method * that has the same parameter type as that component. */ interfaceEntity { public function accept(Visitor $visitor): string; }
/** * The Company Concrete Component. */ classCompanyimplementsEntity { private $name;
/** * @var Department[] */ private $departments;
public function __construct(string $name, array $departments) { $this->name = $name; $this->departments = $departments; }
public function getName(): string { return $this->name; }
public function getDepartments(): array { return $this->departments; }
// ...
public function accept(Visitor $visitor): string { // See, the Company component must call the visitCompany method. The // same principle applies to all components. return $visitor->visitCompany($this); } }
/** * The Department Concrete Component. */ classDepartmentimplementsEntity { private $name;
/** * @var Employee[] */ private $employees;
public function __construct(string $name, array $employees) { $this->name = $name; $this->employees = $employees; }
public function getName(): string { return $this->name; }
public function getEmployees(): array { return $this->employees; }
public function getCost(): int { $cost = 0; foreach ($this->employees as $employee) { $cost += $employee->getSalary(); }
return $cost; }
// ...
public function accept(Visitor $visitor): string { return $visitor->visitDepartment($this); } }
public function __construct(string $name, string $position, int $salary) { $this->name = $name; $this->position = $position; $this->salary = $salary; }
public function getName(): string { return $this->name; }
public function getPosition(): string { return $this->position; }
public function getSalary(): int { return $this->salary; }
// ...
public function accept(Visitor $visitor): string { return $visitor->visitEmployee($this); } }
/** * The Visitor interface declares a set of visiting methods for each of the * Concrete Component classes. */ interfaceVisitor { public function visitCompany(Company $company): string;
public function visitDepartment(Department $department): string;
public function visitEmployee(Employee $employee): string; }
/** * The Concrete Visitor must provide implementations for every single class of * the Concrete Components. */ classSalaryReportimplementsVisitor { public function visitCompany(Company $company): string { $output = ""; $total = 0;
$100,000.00 Albert Falmore (designer) $100,000.00 Ali Halabay (programmer) $ 90,000.00 Sarah Konor (programmer) $ 31,000.00 Monica Ronaldino (QA engineer) $ 30,000.00 James Smith (QA engineer)
--Tech Support (USD199,000.00)
$ 70,000.00 Larry Ulbrecht (supervisor) $ 30,000.00 Elton Pale (operator) $ 30,000.00 Rajeet Kumar (operator) $ 34,000.00 John Burnovsky (operator) $ 35,000.00 Sergey Korolev (operator)
Client: ...or just for a single department:
Tech Support (USD199,000.00)
$ 70,000.00 Larry Ulbrecht (supervisor) $ 30,000.00 Elton Pale (operator) $ 30,000.00 Rajeet Kumar (operator) $ 34,000.00 John Burnovsky (operator) $ 35,000.00 Sergey Korolev (operator)
classConcreteComponentA(Component): """ Each Concrete Component must implement the `accept` method in such a way that it calls the visitor's method corresponding to the component's class. """
defaccept(self, visitor: Visitor) -> None: """ Note that we're calling `visitConcreteComponentA`, which matches the current class name. This way we let the visitor know the class of the component it works with. """
visitor.visit_concrete_component_a(self)
defexclusive_method_of_concrete_component_a(self) -> str: """ Concrete Components may have special methods that don't exist in their base class or interface. The Visitor is still able to use these methods since it's aware of the component's concrete class. """
return"A"
classConcreteComponentB(Component): """ Same here: visitConcreteComponentB => ConcreteComponentB """
classVisitor(ABC): """ The Visitor Interface declares a set of visiting methods that correspond to component classes. The signature of a visiting method allows the visitor to identify the exact class of the component that it's dealing with. """
""" Concrete Visitors implement several versions of the same algorithm, which can work with all concrete component classes. You can experience the biggest benefit of the Visitor pattern when using it with a complex object structure, such as a Composite tree. In this case, it might be helpful to store some intermediate state of the algorithm while executing visitor's methods over various objects of the structure. """
defclient_code(components: List[Component], visitor: Visitor) -> None: """ The client code can run visitor operations over any set of elements without figuring out their concrete classes. The accept operation directs a call to the appropriate operation in the visitor object. """
# ... for component in components: component.accept(visitor) # ...
if __name__ == "__main__": components = [ConcreteComponentA(), ConcreteComponentB()]
print("The client code works with all visitors via the base Visitor interface:") visitor1 = ConcreteVisitor1() client_code(components, visitor1)
print("It allows the same client code to work with different types of visitors:") visitor2 = ConcreteVisitor2() client_code(components, visitor2)
Output.txt: 执行结果
1 2 3 4 5 6
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1 It allows the same client code to work with different types of visitors: A + ConcreteVisitor2 B + ConcreteVisitor2
# The Component interface declares an `accept` method that should take the base # visitor interface as an argument. classComponent # @abstract # # @param [Visitor] visitor defaccept(_visitor) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Each Concrete Component must implement the `accept` method in such a way that # it calls the visitor's method corresponding to the component's class. classConcreteComponentA < Component # Note that we're calling `visitConcreteComponentA`, which matches the current # class name. This way we let the visitor know the class of the component it # works with. defaccept(visitor) visitor.visit_concrete_component_a(self) end
# Concrete Components may have special methods that don't exist in their base # class or interface. The Visitor is still able to use these methods since # it's aware of the component's concrete class. defexclusive_method_of_concrete_component_a 'A' end end
# Same here: visit_concrete_component_b => ConcreteComponentB classConcreteComponentB < Component # @param [Visitor] visitor defaccept(visitor) visitor.visit_concrete_component_b(self) end
defspecial_method_of_concrete_component_b 'B' end end
# The Visitor Interface declares a set of visiting methods that correspond to # component classes. The signature of a visiting method allows the visitor to # identify the exact class of the component that it's dealing with. classVisitor # @abstract # # @param [ConcreteComponentA] element defvisit_concrete_component_a(_element) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end
# @abstract # # @param [ConcreteComponentB] element defvisit_concrete_component_b(_element) raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'" end end
# Concrete Visitors implement several versions of the same algorithm, which can # work with all concrete component classes. # # You can experience the biggest benefit of the Visitor pattern when using it # with a complex object structure, such as a Composite tree. In this case, it # might be helpful to store some intermediate state of the algorithm while # executing visitor's methods over various objects of the structure. classConcreteVisitor1 < Visitor defvisit_concrete_component_a(element) puts "#{element.exclusive_method_of_concrete_component_a} + #{self.class}" end
defvisit_concrete_component_b(element) puts "#{element.special_method_of_concrete_component_b} + #{self.class}" end end
classConcreteVisitor2 < Visitor defvisit_concrete_component_a(element) puts "#{element.exclusive_method_of_concrete_component_a} + #{self.class}" end
defvisit_concrete_component_b(element) puts "#{element.special_method_of_concrete_component_b} + #{self.class}" end end
# The client code can run visitor operations over any set of elements without # figuring out their concrete classes. The accept operation directs a call to # the appropriate operation in the visitor object. defclient_code(components, visitor) # ... components.each do |component| component.accept(visitor) end # ... end
puts 'The client code works with all visitors via the base Visitor interface:' visitor1 = ConcreteVisitor1.new client_code(components, visitor1)
puts 'It allows the same client code to work with different types of visitors:' visitor2 = ConcreteVisitor2.new client_code(components, visitor2)
output.txt: 执行结果
1 2 3 4 5 6
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1 It allows the same client code to work with different types of visitors: A + ConcreteVisitor2 B + ConcreteVisitor2
/// The Component interface declares an `accept` method that should take the /// base visitor interface as an argument. protocolComponent {
funcaccept(_visitor: Visitor) }
/// Each Concrete Component must implement the `accept` method in such a way /// that it calls the visitor's method corresponding to the component's class. classConcreteComponentA: Component {
/// Note that we're calling `visitConcreteComponentA`, which matches the /// current class name. This way we let the visitor know the class of the /// component it works with. funcaccept(_visitor: Visitor) { visitor.visitConcreteComponentA(element: self) }
/// Concrete Components may have special methods that don't exist in their /// base class or interface. The Visitor is still able to use these methods /// since it's aware of the component's concrete class. funcexclusiveMethodOfConcreteComponentA() -> String { return"A" } }
/// The Visitor Interface declares a set of visiting methods that correspond to /// component classes. The signature of a visiting method allows the visitor to /// identify the exact class of the component that it's dealing with. protocolVisitor {
/// Concrete Visitors implement several versions of the same algorithm, which /// can work with all concrete component classes. /// /// You can experience the biggest benefit of the Visitor pattern when using it /// with a complex object structure, such as a Composite tree. In this case, it /// might be helpful to store some intermediate state of the algorithm while /// executing visitor's methods over various objects of the structure. classConcreteVisitor1: Visitor {
/// The client code can run visitor operations over any set of elements without /// figuring out their concrete classes. The accept operation directs a call to /// the appropriate operation in the visitor object. classClient { // ... staticfuncclientCode(components: [Component], visitor: Visitor) { // ... components.forEach({ $0.accept(visitor) }) // ... } // ... }
/// Let's see how it all works together. classVisitorConceptual: XCTestCase {
functest() { let components: [Component] = [ConcreteComponentA(), ConcreteComponentB()]
print("The client code works with all visitors via the base Visitor interface:\n") let visitor1 =ConcreteVisitor1() Client.clientCode(components: components, visitor: visitor1)
print("\nIt allows the same client code to work with different types of visitors:\n") let visitor2 =ConcreteVisitor2() Client.clientCode(components: components, visitor: visitor2) } }
Output.txt: 执行结果
1 2 3 4 5 6 7 8 9 10 11 12
The client code works with all visitors via the base Visitor interface:
A + ConcreteVisitor1
B + ConcreteVisitor1
It allows the same client code to work with different types of visitors:
/// Client code traverses notifications with visitors and checks whether a /// notification is in a blacklist and should be shown in accordance with a /// current SilencePolicy
print("\nClient: Using \(policy.description) and \(blackList.description)")
notifications.forEach { item in
guard!item.accept(visitor: blackList) else { print("\tWARNING: "+ item.description +" is in a black list") return }
if item.accept(visitor: policy) { print("\t"+ item.description +" notification will be shown") } else { print("\t"+ item.description +" notification will be silenced") } } }
Client: Using Default Policy Visitor and Black List Visitor Email notification will be shown SMS notification will be shown WARNING: Push is in a black list
Client: Using Night Policy Visitor and Black List Visitor Email notification will be silenced SMS notification will be shown WARNING: Push is in a black list
/** * The Component interface declares an `accept` method that should take the base * visitor interface as an argument. */ interfaceComponent { accept(visitor: Visitor): void; }
/** * Each Concrete Component must implement the `accept` method in such a way that * it calls the visitor's method corresponding to the component's class. */ classConcreteComponentAimplementsComponent { /** * Note that we're calling `visitConcreteComponentA`, which matches the * current class name. This way we let the visitor know the class of the * component it works with. */ publicaccept(visitor: Visitor): void { visitor.visitConcreteComponentA(this); }
/** * Concrete Components may have special methods that don't exist in their * base class or interface. The Visitor is still able to use these methods * since it's aware of the component's concrete class. */ publicexclusiveMethodOfConcreteComponentA(): string { return'A'; } }
/** * The Visitor Interface declares a set of visiting methods that correspond to * component classes. The signature of a visiting method allows the visitor to * identify the exact class of the component that it's dealing with. */ interfaceVisitor { visitConcreteComponentA(element: ConcreteComponentA): void;
/** * Concrete Visitors implement several versions of the same algorithm, which can * work with all concrete component classes. * * You can experience the biggest benefit of the Visitor pattern when using it * with a complex object structure, such as a Composite tree. In this case, it * might be helpful to store some intermediate state of the algorithm while * executing visitor's methods over various objects of the structure. */ classConcreteVisitor1implementsVisitor { publicvisitConcreteComponentA(element: ConcreteComponentA): void { console.log(`${element.exclusiveMethodOfConcreteComponentA()} + ConcreteVisitor1`); }
/** * The client code can run visitor operations over any set of elements without * figuring out their concrete classes. The accept operation directs a call to * the appropriate operation in the visitor object. */ functionclientCode(components: Component[], visitor: Visitor) { // ... for (const component of components) { component.accept(visitor); } // ... }
console.log('The client code works with all visitors via the base Visitor interface:'); const visitor1 = newConcreteVisitor1(); clientCode(components, visitor1); console.log('');
console.log('It allows the same client code to work with different types of visitors:'); const visitor2 = newConcreteVisitor2(); clientCode(components, visitor2);
Output.txt: 执行结果
1 2 3 4 5 6 7
The client code works with all visitors via the base Visitor interface: A + ConcreteVisitor1 B + ConcreteVisitor1
It allows the same client code to work with different types of visitors: A + ConcreteVisitor2 B + ConcreteVisitor2
func(a *areaCalculator) visitForSquare(s *square) { // Calculate area for square. // Then assign in to the area instance variable. fmt.Println("Calculating area for square") }
func(a *areaCalculator) visitForCircle(s *circle) { fmt.Println("Calculating area for circle") } func(a *areaCalculator) visitForrectangle(s *rectangle) { fmt.Println("Calculating area for rectangle") }
func(a *middleCoordinates) visitForSquare(s *square) { // Calculate middle point coordinates for square. // Then assign in to the x and y instance variable. fmt.Println("Calculating middle point coordinates for square") }
func(a *middleCoordinates) visitForCircle(c *circle) { fmt.Println("Calculating middle point coordinates for circle") } func(a *middleCoordinates) visitForrectangle(t *rectangle) { fmt.Println("Calculating middle point coordinates for rectangle") }