From 1baf6dd7226d166e27d8274dd3cd994fd616ade0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 24 May 2024 09:33:02 +0300 Subject: [PATCH] docs: update acyclic visitor --- acyclic-visitor/README.md | 78 +++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/acyclic-visitor/README.md b/acyclic-visitor/README.md index ab2304402..25127a599 100644 --- a/acyclic-visitor/README.md +++ b/acyclic-visitor/README.md @@ -5,6 +5,8 @@ language: en tag: - Decoupling - Extensibility + - Interface + - Object composition --- ## Intent @@ -15,7 +17,7 @@ The Acyclic Visitor pattern decouples operations from an object hierarchy, allow Real world example -> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based on filtering criteria (is it Unix or DOS compatible modem). +> An analogous real-world example of the Acyclic Visitor pattern is a museum guide system. Imagine a museum with various exhibits like paintings, sculptures, and historical artifacts. The museum has different types of guides (audio guide, human guide, virtual reality guide) that provide information about each exhibit. Instead of modifying the exhibits every time a new guide type is introduced, each guide implements an interface to visit different exhibit types. This way, the museum can add new types of guides without altering the existing exhibits, ensuring that the system remains extensible and maintainable without forming any dependency cycles. In plain words @@ -27,6 +29,8 @@ In plain words **Programmatic Example** +We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based on filtering criteria (is it Unix or DOS compatible modem). + Here's the `Modem` hierarchy. ```java @@ -35,7 +39,8 @@ public abstract class Modem { } public class Zoom extends Modem { - ... + + // Other properties and methods... @Override public void accept(ModemVisitor modemVisitor) { @@ -48,7 +53,8 @@ public class Zoom extends Modem { } public class Hayes extends Modem { - ... + + // Other properties and methods... @Override public void accept(ModemVisitor modemVisitor) { @@ -61,7 +67,7 @@ public class Hayes extends Modem { } ``` -Next we introduce the `ModemVisitor` hierarchy. +Next, we introduce the `ModemVisitor` hierarchy. ```java public interface ModemVisitor { @@ -79,7 +85,8 @@ public interface AllModemVisitor extends ZoomVisitor, HayesVisitor { } public class ConfigureForDosVisitor implements AllModemVisitor { - ... + + // Other properties and methods... @Override public void visit(Hayes hayes) { @@ -93,7 +100,8 @@ public class ConfigureForDosVisitor implements AllModemVisitor { } public class ConfigureForUnixVisitor implements ZoomVisitor { - ... + + // Other properties and methods... @Override public void visit(Zoom zoom) { @@ -105,28 +113,32 @@ public class ConfigureForUnixVisitor implements ZoomVisitor { Finally, here are the visitors in action. ```java - var conUnix=new ConfigureForUnixVisitor(); - var conDos=new ConfigureForDosVisitor(); - var zoom=new Zoom(); - var hayes=new Hayes(); - hayes.accept(conDos); - zoom.accept(conDos); - hayes.accept(conUnix); - zoom.accept(conUnix); +public static void main(String[] args) { + var conUnix = new ConfigureForUnixVisitor(); + var conDos = new ConfigureForDosVisitor(); + + var zoom = new Zoom(); + var hayes = new Hayes(); + + hayes.accept(conDos); // Hayes modem with Dos configurator + zoom.accept(conDos); // Zoom modem with Dos configurator + hayes.accept(conUnix); // Hayes modem with Unix configurator + zoom.accept(conUnix); // Zoom modem with Unix configurator +} ``` Program output: ``` - // Hayes modem used with Dos configurator. - // Zoom modem used with Dos configurator. - // Only HayesVisitor is allowed to visit Hayes modem - // Zoom modem used with Unix configurator. +09:15:11.125 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForDosVisitor -- Hayes modem used with Dos configurator. +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForDosVisitor -- Zoom modem used with Dos configurator. +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.Hayes -- Only HayesVisitor is allowed to visit Hayes modem +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor -- Zoom modem used with Unix configurator. ``` ## Class diagram -![alt text](./etc/acyclic-visitor.png "Acyclic Visitor") +![Acyclic Visitor](./etc/acyclic-visitor.png "Acyclic Visitor") ## Applicability @@ -140,28 +152,32 @@ This pattern can be used: ## Tutorials -* [Acyclic Visitor Pattern Example](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html) +* [The Acyclic Visitor Pattern (Code Crafter)](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html) ## Consequences Benefits: -* No dependency cycles between class hierarchies. -* No need to recompile all the visitors if a new one is added. -* Does not cause compilation failure in existing visitors if class hierarchy has a new member. +* Extensible: New operations can be added easily without changing the object structure. +* Decoupled: Reduces coupling between the objects and the operations on them. +* No dependency cycles: Ensures acyclic dependencies, improving maintainability and reducing complexity. Trade-offs: -* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors. -* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy. +* Increased complexity: Can introduce additional complexity with the need for multiple visitor interfaces. +* Maintenance overhead: Modifying the object hierarchy requires updating all visitors. -## Related patterns +## Related Patterns -* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/) +* [Composite](https://java-design-patterns.com/patterns/composite/): Often used in conjunction with Acyclic Visitor to allow treating individual objects and compositions uniformly. +* [Decorator](https://java-design-patterns.com/patterns/decorator/): Can be used alongside to add responsibilities to objects dynamically. +* [Visitor](https://java-design-patterns.com/patterns/visitor/): The Acyclic Visitor pattern is a variation of the Visitor pattern that avoids cyclic dependencies. ## Credits -* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf) -* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) -* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) +* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML](https://amzn.to/4bOtzwF) +* [Acyclic Visitor (Robert C. Martin)](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf) +* [Acyclic Visitor (WikiWikiWeb)](https://wiki.c2.com/?AcyclicVisitor)