Visitor Design Pattern in Swift

The Visitor pattern is a pattern that allows developers to separate the algorithm from the object structure on which it operates. It allows developers to define a new operation without changing the classes of the objects on which it operates. The Visitor pattern involves two main components: the Visitor and the Visitable.
The Visitor is an interface that defines a visit method for each type of object in the object structure. Each visit method accepts a reference to a specific object and performs a specific operation on that object.
The Visitable is an interface that defines an accept method. This method accepts a Visitor object and calls the appropriate visit method on the Visitor.
The main advantage of the Visitor pattern is that it allows developers to add new operations to an object structure without changing the classes of the objects in the structure.
Swift Code Example
To demonstrate how the Visitor pattern can be implemented in Swift, let’s consider a simple example of a shopping cart. Suppose we have a shopping cart that contains a list of items. Each item can be of a different type, such as a book, a DVD, or a piece of clothing.
Our goal is to implement a discount system that provides a discount on the total price of the shopping cart based on the type of item. We can use the Visitor pattern to implement this discount system.
First, we define the Visitable interface that contains the accept method:
protocol Visitable {
func accept(visitor: Visitor)
}
Next, we define the Visitor interface that contains the visit methods for each type of item:
protocol Visitor {
func visit(book: Book)
func visit(dvd: DVD)
func visit(clothing: Clothing)
}
We then create the concrete classes that represent the items in our shopping cart:
class Book: Visitable {
let title: String
let price: Double
init(title: String, price: Double) {
self.title = title
self.price = price
}
func accept(visitor: Visitor) {
visitor.visit(book: self)
}
}
class DVD: Visitable {
let title: String
let price: Double
init(title: String, price: Double) {
self.title = title
self.price = price
}
func accept(visitor: Visitor) {
visitor.visit(dvd: self)
}
}
class Clothing: Visitable {
let name: String
let price: Double
init(name: String, price: Double) {
self.name = name
self.price = price
}
func accept(visitor: Visitor) {
visitor.visit(clothing: self)
}
}
We then create the concrete Visitor that implements the discount system:
class DiscountVisitor: Visitor {
var totalDiscount: Double = 0.0
func visit(book: Book) {
totalDiscount += book.price * 0.1
}
func visit(dvd: DVD) {
totalDiscount += dvd.price * 0.05
}
func visit(clothing: Clothing) {
totalDiscount += clothing.price * 0.2
}
}
Finally, we can use the Visitor pattern to calculate the total price of the shopping cart with the discount applied:
let cart: [Visitable] = [Book(title: "Swift Programming", price: 100.0), DVD(title: "Avengers", price: 50.0), Clothing(name: "T-Shirt", price: 30.0)]
let discountVisitor = DiscountVisitor()
for item in cart {
item.accept(visitor: discountVisitor)
}
let totalPrice = cart.reduce(0) { $0 + ($1 as! Visitable).price } - discountVisitor.totalDiscount
print("Total price with discount: (totalPrice)") // Output: Total price with discount: 165.0
In the above code, we create a shopping cart that contains a Book, a DVD, and a piece of Clothing. We then create an instance of the DiscountVisitor that implements the discount system.
We loop through the items in the shopping cart and call the accept method on each item passing the DiscountVisitor as an argument. This calls the appropriate visit method on the DiscountVisitor based on the type of item.
Finally, we calculate the total price of the shopping cart with the discount applied by reducing the array of items and subtracting the total discount from the total price.
Conclusion
In this article, we explored the Visitor pattern, a behavioural design pattern that allows developers to add new operations to an object structure without changing the classes of the objects in the structure. We demonstrated how the Visitor pattern can be implemented in Swift with a code example that implements a discount system for a shopping cart.
The Visitor pattern is a powerful pattern that can help developers to improve the flexibility and maintainability of their code. By separating the algorithm from the object structure, developers can add new operations to their code without modifying existing code, leading to more modular and maintainable software systems.
Please 👏🏻 if you like this post. It will motivate me to continue creating high-quality content like this one.
Support Me
Thank you for taking the time to read my blog post! If you found it valuable, I would greatly appreciate it if you could share the post on Twitter and LinkedIn, etc. Your support in spreading the word about my content means a lot to me. Thank you again!
Follow me
I hope you found this post helpful. If you want to stay up-to-date with my latest work, be sure to follow me on my page or my Twitter.