Visitor Pattern Example

Updated
Dec 9, 2019 7:27 AM
Created
Dec 9, 2019 7:27 AM
Tags
SwiftMemo
Keywords
Date
import Foundation

struct Wrapper: Hashable {
  var groups: [BookGroup] = []
}

struct BookGroup: Hashable {
  
  var name: String
  var books: [Book] = []
}

struct Book: Hashable {
  
  var name: String
  var author: Author
}

struct Author: Hashable {
  
  var name: String
}

let authorA = Author(name: "Author-A")
let authorB = Author(name: "Author-B")
let authorC = Author(name: "Author-C")

let groupA = BookGroup(name: "A", books: [
  Book(name: "A-Book-1", author: authorA),
  Book(name: "A-Book-2", author: authorA),
  Book(name: "A-Book-3", author: authorB)
])
let groupB = BookGroup(name: "B", books: [
  Book(name: "B-Book-1", author: authorC),
  Book(name: "B-Book-2", author: authorA),
  Book(name: "B-Book-3", author: authorB)
])
let groupC = BookGroup(name: "C", books: [
  Book(name: "C-Book-1", author: authorA),
  Book(name: "C-Book-2", author: authorC),
  Book(name: "C-Book-3", author: authorB)
])

let wrapper = Wrapper(groups: [groupA, groupB, groupC])

extension Wrapper {
  func accept(_ visitor: Visitor) {
    visitor.visit(self)
    groups.forEach {
      $0.accept(visitor)
    }
  }
}

extension BookGroup {
  func accept(_ visitor: Visitor) {
    visitor.visit(self)
    books.forEach {
      $0.accept(visitor)
    }
  }
}

extension Book {
  func accept(_ visitor: Visitor) {
    visitor.visit(self)
    author.accept(visitor)
  }
}

extension Author {
  func accept(_ visitor: Visitor) {
    visitor.visit(self)
  }
}

class Visitor {
  
  func visit(_ wraper: Wrapper) {
   
  }
    
  func visit(_ group: BookGroup) {
   
  }
  
  func visit(_ book: Book) {
    
  }
  
  func visit(_ author: Author) {
    
  }
  
}

class CollectAuthorVisitor: Visitor {
  
  var authors = Set<Author>()
  
  override func visit(_ author: Author) {
    super.visit(author)
    authors.insert(author)
  }
  
}

class CollectBookCountVisitor: Visitor {
  
  var bookCount = 0
  
  override func visit(_ book: Book) {
    super.visit(book)
    bookCount += 1
  }
    
}

let authorVisitor = CollectAuthorVisitor()
let countVisitor = CollectBookCountVisitor()

wrapper.accept(authorVisitor)
wrapper.accept(countVisitor)

print(authorVisitor.authors)
print(countVisitor.bookCount)