swift - 如何在 Swift 中使用访问者模式减少样板文件?

标签 swift design-patterns swift2 visitor-pattern

我正在为一个工作项目在 Swift 2.2 中实现访问者模式。

这样我就不必精简我的源代码并节省时间,我将使用 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" }
}

我一直试图解决的问题是减少派生自 Planet 的每个类的样板文件。 如您所见,它们都具有相同的函数 duplicated func accept(visitor: PlanetVisitor) { visitor.visit(self) }

我曾尝试在 Planet 协议(protocol)上放置一个默认实现,并在基类上实现它,但由于编译时重载解析,Swift 似乎不允许这样做。

例子:

协议(protocol)的默认实现:

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

基类:

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

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

有谁知道 accept 函数可以通用并自动应用于从 Planet 派生的每个具体类的方法吗?这不是一个关键问题,但却是一个很大的难题!

最佳答案

简短回答:不可能,这是设计使然。

访客模式适用于行星数量稳定但访客数量未知的情况。因此,您计划在访问者中进行 future 的扩展,一次编写此样板。然后可以在不改变行星的情况下添加更多访客。

在大型项目中,您可能会使用代码生成。


不推荐,您的替代方案是直接切换行星,不需要样板代码:

func foo(planet: Planet) {
    if planet is PlanetAlderaan {
        name = "Alderaan"
    }
    else if planet is PlanetCoruscant {
        name = "Coruscant"
    }
    else if planet is PlanetTatooine {
        name = "Tatooine"
    }
}

这很容易出错,因为您很容易忘记行星。访问者模式强制您为所有情况编写代码,否则将无法编译。

关于swift - 如何在 Swift 中使用访问者模式减少样板文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40759214/

相关文章:

ios - 覆盖方法的 Swift 文档注释?

ios - 如何在 Swift 中向上滚动整个表格 View ?

linux - Linux/Windows 上 Swift 的 GUI 生成器

java - 寻找 OSGi 设计模式

ios - CBCentralManagerState(iOS 5.x 至 9.x)和 CBManagerState(iOS 10.x 或更高版本)之间的 CoreBluetooth 兼容性问题

C#,从引用的项目访问类

c++ - 具有参数化构造函数的抽象工厂

iOS - UIBezierPath 使起始角度始终垂直

swift - 函数不会等到数据下载完毕

swift - 如何在 Swift 中获取后台文件下载任务的引用?