传统上,在“模板方法”模式中,基类实现一些算法并遵循派生类的特定行为。这在 C++/C#/Java 之类的语言中效果很好,因为您可以在这些方法上使用“ protected ”以将它们对调用者隐藏,但对派生类保持可见。例如,在 GoF 书中,您有类似的内容:

class Application
{
    void CreateDocument() { ..., this->DoCreateDocument() }
    protected void DoCreateDocument() { } // override for custom behavior
}

这使 Application 的公共(public)接口(interface)保持干净。在 Swift 中,因为不能使用 protected ,所以公共(public)接口(interface)不干净。我不希望 Application 的用户看到 DoCreateDocument

所以我正在尝试另一种方法,它不是使用 DoCreateDocument 的方法,而是尝试定义一个闭包并使用“仿函数”模式。
class Application
{
    typealias ActionFunc = () -> ()
    private let doCreateDocument : ActionFunc
    init(a : ActionFunc) { self.doCreateDocument = a }
    func CreateDocument() {
        self.doCreateDocument()
    }
}

所以这个类看起来不错——公共(public)接口(interface)很干净。但是,实际使用它是不可能的。

显而易见的方法是使用派生类:
class DoApplication : Application
{
    init() {
        super.init(
            a : {
                // This would work, but you cannot use self here!
                self. // anything with self. is an error
            })
    }
}

这种方法的问题在于,在初始化程序中,您不能将闭包传递给使用 super.initself 。我收到错误 self used before super.init

这基本上使它变得无用,因为您无法访问任何状态变量。

但是,如果您不在 doCreateDocument 中初始化 init ,则需要公开某种 setter - 同样,缺少 protected 意味着 setter 位于公共(public) API 上。哎呀。

那么有没有什么方法可以干净地实现保持界面干净的模板模式呢?

最佳答案

我知道这是一个丑陋的黑客,但它有效。

class DoApplication: Application {
    init() {
        var doCreateDocument: (Application.ActionFunc)!
        super.init(a: { doCreateDocument() })
        doCreateDocument = { [unowned self] in
            self.foo()
        }
    }

    func foo() {
        println("DoApplication.foo");
    }
}

或者,您可以将 self 传递给 doCreateDocument :
class Application {
    typealias ActionFunc = (Application) -> ()
    private let doCreateDocument : ActionFunc

    init(a : ActionFunc) { self.doCreateDocument = a }

    func CreateDocument() {
        self.doCreateDocument(self)
    }
}

class DoApplication : Application {
    init() {
        super.init(a : { _self in
            let _self = _self as! DoApplication

            _self.foo()
        })
    }
    func foo() {
        println("DoApplication.foo");
    }
}

关于Swift:如何支持 "template method"设计模式(因为 Swift 没有保护)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31757514/

10-11 14:50