mercredi 23 novembre 2016

How can I reduce boilerplate with the visitor pattern in Swift?

I am implementing the visitor pattern in Swift 2.2 for a project at work.

So that I don't have to boil down my source code and to save me some time I will use an example of visitor pattern in swift by Oktawian Chojnacki.

protocol PlanetVisitor {
    func visit(planet: PlanetAlderaan)
    func visit(planet: PlanetCoruscant)
    func visit(planet: PlanetTatooine)
}

protocol Planet {
    func accept(visitor: PlanetVisitor)
}

class PlanetAlderaan: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(self) }
}
class PlanetCoruscant: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(self) }
}
class PlanetTatooine: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(self) }
}

class NameVisitor: PlanetVisitor {
    var name = ""

    func visit(planet: PlanetAlderaan)  { name = "Alderaan" }
    func visit(planet: PlanetCoruscant) { name = "Coruscant" }
    func visit(planet: PlanetTatooine)  { name = "Tatooine" }
}

The problem I have been trying to solve is to reduce the boilerplate on each class that derives from Planet. As you can see they all have same function duplicated func accept(visitor: PlanetVisitor) { visitor.visit(self) }.

I have tried putting a default implementation on the Planet protocol and implementing it on a base class and Swift does not seem to allow it due to compile time overload resolution.

Examples:

Default Implementation on Protocol:

extension Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(self) }
}

Base Class:

class PlanetBase: Planet {
    func accept(visitor: PlanetVisitor) { visitor.visit(self) }
}

class PlanetAlderaan: PlanetBase {}
class PlanetCoruscant: PlanetBase {}
class PlanetTatooine: PlanetBase {}

Does anyone know of a way that the accept function could be made generic and applied automatically to each concrete class that derives from Planet? It is not a critical issue but it is a great puzzle!

Aucun commentaire:

Enregistrer un commentaire