The Visitor Design Pattern Detailed Illustration with an Office Furniture System

Mohammed Muwanga
5 min readAug 15, 2024

--

The Visitor Design Pattern Detailed Illustration with an Office Furniture System — Muwanga Mohammed Web designs

The Visitor Design Pattern is a behavioral design pattern for specifically adding further operations to objects without modifying their structure. Just as the name sounds, a visitor holds the functionality you want add to an object. For instance, you call an electrician to you home to renovate an electrical issue in your bedroom. This guy already knows every thing related to electrical home renovation. You simply just need to set an appointment with him, he comes and does his operation in your bedroom. This design pattern promotes the separation of algorithms from the objects on which they operate. It makes it easier to add new operations to existing object structures without altering those structures.

To illustrate how the Visitor pattern works, let’s apply it to an office furniture online system.

Office Furniture Online System: Use Case

Imagine you have an online store that sells various types of office furniture, such as desks, chairs, and filing cabinets. Each of these furniture types is represented by a class in your system, and each class has different properties and methods. As the business grows, the system requires additional functionalities, such as calculating shipping costs, applying discounts, or generating product descriptions.

Instead of modifying the existing furniture classes each time a new functionality is required, you can use the Visitor Design Pattern to add these operations without altering the furniture classes themselves.

Key Components of the Visitor Pattern

Visitor Interface:

  • The Visitor interface declares visit methods for each type of element in the object structure. These methods define what should be done when visiting an element.
  • Example: FurnitureVisitor with methods visitDesk(Desk $desk), visitChair(Chair $chair), and visitCabinet(Cabinet $cabinet).

Concrete Visitor:

  • A ConcreteVisitor implements the operations defined in the Visitor interface. It contains the logic that must be executed when visiting each element.
  • Example: ShippingCostVisitor calculates shipping costs, DiscountVisitor applies discounts, and DescriptionVisitor generates product descriptions.

Element Interface:

  • The Element interface declares an accept method that takes a visitor as an argument.
  • Example: FurnitureItem with an accept(FurnitureVisitor $visitor) method.

Concrete Elements:

  • ConcreteElements implement the Element interface and define how they accept a visitor by invoking the visitor’s corresponding method.
  • Example: Desk, Chair, and Cabinet classes that implement FurnitureItem and have an accept method.

Object Structure:

  • The ObjectStructure represents a collection of elements that can be visited. It’s responsible for providing access to the elements and may allow the visitor to traverse through them.
  • Example: A FurnitureCollection class containing a list of FurnitureItem objects.

Implementation Example

Implementation of Visitor Design Pattern using Office Furniture Store Online System — Mohammed Muwanga

Let’s walk through an example of how the Visitor pattern might be implemented in the office furniture online system.

1. Visitor Interface:

interface FurnitureVisitor {
public function visitDesk(Desk $desk);
public function visitChair(Chair $chair);
public function visitCabinet(Cabinet $cabinet);
}

2. Concrete Visitor:

class ShippingCostVisitor implements FurnitureVisitor {
public function visitDesk(Desk $desk) {
// Calculate shipping cost based on desk dimensions and weight
return $desk->getWeight() * 0.5 + $desk->getDimensions();
}

public function visitChair(Chair $chair) {
// Calculate shipping cost based on chair weight and size
return $chair->getWeight() * 0.3 + $chair->getSize();
}

public function visitCabinet(Cabinet $cabinet) {
// Calculate shipping cost based on cabinet dimensions and weight
return $cabinet->getWeight() * 0.7 + $cabinet->getDimensions();
}
}

3. Element Interface:

interface FurnitureItem {
public function accept(FurnitureVisitor $visitor);
}

4. Concrete Elements:

class Desk implements FurnitureItem {
private $weight;
private $dimensions;

public function __construct($weight, $dimensions) {
$this->weight = $weight;
$this->dimensions = $dimensions;
}

public function getWeight() {
return $this->weight;
}

public function getDimensions() {
return $this->dimensions;
}

public function accept(FurnitureVisitor $visitor) {
return $visitor->visitDesk($this);
}
}

class Chair implements FurnitureItem {
private $weight;
private $size;

public function __construct($weight, $size) {
$this->weight = $weight;
$this->size = $size;
}

public function getWeight() {
return $this->weight;
}

public function getSize() {
return $this->size;
}

public function accept(FurnitureVisitor $visitor) {
return $visitor->visitChair($this);
}
}

class Cabinet implements FurnitureItem {
private $weight;
private $dimensions;

public function __construct($weight, $dimensions) {
$this->weight = $weight;
$this->dimensions = $dimensions;
}

public function getWeight() {
return $this->weight;
}

public function getDimensions() {
return $this->dimensions;
}

public function accept(FurnitureVisitor $visitor) {
return $visitor->visitCabinet($this);
}
}

5. Object Structure:

class FurnitureCollection {
private $items = [];

public function addItem(FurnitureItem $item) {
$items[] = $item;
}

public function accept(FurnitureVisitor $visitor) {
foreach ($this->items as $item) {
$item->accept($visitor);
}
}
}

Usage Example:

// Create furniture items
$desk = new Desk(50, 120);
$chair = new Chair(20, 80);
$cabinet = new Cabinet(70, 150);

// Add items to collection
$furnitureCollection = new FurnitureCollection();
$furnitureCollection->addItem($desk);
$furnitureCollection->addItem($chair);
$furnitureCollection->addItem($cabinet);

// Create a visitor to calculate shipping costs
$shippingCostVisitor = new ShippingCostVisitor();

// Apply the visitor to the collection
$furnitureCollection->accept($shippingCostVisitor);

Advantages of Using the Visitor Pattern

Separation of Concerns:

The Visitor pattern allows you to separate operations from the objects they operate on. This keeps your classes cleaner and more focused on their primary responsibilities.

Extensibility:

You can easily add new operations to your object structure without modifying the objects themselves. Adding a new visitor is straightforward and doesn’t require changes to the existing code.

Open/Closed Principle: — [SOLID PRINCIPLES]

The pattern adheres to the Open/Closed Principle, which states that classes should be open for extension but closed for modification.

The SOLID principles are a set of five design guidelines — Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion . They particularly promote better software design, encouraging maintainable, scalable, and robust code.

Considerations and Drawbacks

Complexity:

The Visitor pattern can introduce additional complexity, especially in systems with many different types of elements. Each new visitor requires implementing visit methods for each element type.

Double Dispatch:

The Visitor pattern relies on double dispatch, meaning it involves two method calls to execute an operation: one on the element to accept the visitor and one on the visitor to perform the operation. This can lead to more complex code structures.

Conclusion

The Visitor Design Pattern is a powerful tool for adding new operations to an existing class hierarchy without altering the classes themselves. In an office furniture online system, it allows you to add features like shipping cost calculations, discount applications, and product descriptions in a modular, maintainable way. This Visitor pattern, will keep your system flexible and extendable while maintaining new features to be added with minimal disruption to existing code.

Read More about Strategy Design Pattern part of Behavioral Design Pattern commonly used

Sign up to discover human stories that deepen your understanding of the world.

--

--

Mohammed Muwanga
Mohammed Muwanga

Written by Mohammed Muwanga

Web Design, Development, SEO and Ergonomics

No responses yet

Write a response