Swift:如何支持“模板方法”设计模式(因为Swift没有保护)?

传统上,在“模板方法”模式中,基类实现一些算法并遵循特定行为的派生类.这在C/C++#/
Java等语言中运行良好,因为您可以在这些方法上使用“protected”来将它们隐藏在调用者中,但使其对派生类可见.例如,在GoF书中,你有类似的东西:

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

这样可以保持Application的公共接口干净.在Swift中,因为你不能使用protected,所以公共接口不干净.我不希望Application的用户看到DoCreateDocument.

所以我正在尝试另一种方法,而不是使用DoCreateDocument的方法,我试图定义一个闭包并使用“仿函数”模式.

class Application
{
    typealias ActionFunc = () -> ()
    private let doCreateDocument : ActionFunc
    init(a : ActionFunc) { self.doCreateDocument = a }
    func CreateDocument() {
        self.doCreateDocument()
    }
}

所以这个类看起来很好 – 公共接口很干净.但是,实际使用它是不可能的.

显而易见的方法是使用派生类:

class DoApplication : Application
{
    init() {
        super.init(
            a : {
                // This would work, but you cannot use self here!
                self. // anything with self. is an error
            })
    }
}

这种方法的问题在于,在初始化程序中,您无法将闭包传递给使用self的super.init.我在super.init之前得到了自己使用的错误.

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

但是,如果不在init中初始化doCreateDocument,则需要公开某些类型的setter – 同样,缺少protected也意味着setter在公共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");
    }
}
点赞