Visitor design pattern

Идеята на този design pattern e да може ако искаме да добавяме още функционалност към даден обект (Component), да не го дописваме него (обектът), а да имаме друг клас (Visitor), на който да подаваме този обект, и там, използвайки методите му (на предаденият Component) да създадем допълнителната логика.

Или даже по-скоро изцяло да разделим даден клас на части, например оставяйки единият да отговаря само за данните, а в други (visitors) да имаме различните логики за работа с тези данни.
In object-oriented programming and software engineering, the Visitor Design pattern is a way of separating an algorithm from an object data structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle.

Казах „подаваме“, но имах предвид, че по-скоро приемаме „посетителят“ и му подаваме сами себе си с $this с метод, обикновено наречен accept()

public function accept (Visitor $visitor): void
{
    $visitor->visitConcreteComponent($this);
}

Ето как Visitor обектът бива допуснат в нашият Component и той сам си взема дадената инстанция ($this) с помощта на свой метод visitConcreteComponent() и го използва за да създаде допълнителна функционалност в себе си (в класът Visitor).

Този design pattern е едно типично превъплъщение на Open Close SOLID principle и много напомня на Adapter или Decorator и други, на които подаваме даден обект и те го „доразвиват“.

…the visitor design pattern is a way of separating an algorithm from an object data on which it operates…

По този начин основният клас Component може спокойно да остане максимално прост, а за него да създадем N на брой Visitor класа, които да му добавят нужната допълнителна логика. Особено когато това се налага често.

Най-малкото, което печелим е, че няма да претоварим Component класа и да нарушим Single responsibility SOLID принципа, както и няма да му пишем наследници, което значи, че ще използваме composition over inheritance.

Ето я в основни линии идеята на Visitor design pattern – да можем да „разхвърляме“ логиката на даден клас по други класове (Visitors), а не да го претоварваме като пишем цялата логика само в него.

Отделно, представете си че имаме даден алгоритъм, който трябва да реализираме в повече от един клас. Във всеки ли да го реализираме?
Не е ли по-елегантно да го реализираме в един Visitor клас,
и с accept()-овете на тези отделните, повече от един Component-и,
да му ги подаваме, и той (Visitor-ът) да ги „посещава“ и да реализира тази логика, използвайки ги.

Един Component разбира се може да има много Visitor-и. Даже не „да има“, а „да използва“, защото това са два различни класови структури (Component и Visitor), тоест, няма пряка връзка между тях, като наследяване например.

  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. Демек, във отделни Visitors можеш да си капсулираш сходни по смисъл функционалности.
  3. Visitor can visit objects that don’t have a common parent class, as long as it can use the Component functionality.
  4. Accumulating state. Visitors can accumulate state as they visit each element in the object structure. Without a visitor, this state would be passed as extra arguments to the operations that perform the traversal, or they might appear as global variables. Visitor-ите могат да акумулират информация от отделните обекти, които му се подават.
  5. Breaking encapsulation. Visitor’s approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job. As a result, the pattern often forces you to provide public operations that access an element’s internal state, which may compromise its encapsulation.
    Като недостатък, понеже Visitor-ите трябва да могат да използват public функционалността на подаваните им обекти, може да се наложи те (използваните обекти) да имат повече public методи и пропъртита, което може да намали data hiding.

Литература:

https://refactoring.guru/design-patterns/visitor/php/example

Вашият коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *