Swift语言中的抽象函数

kev*_*kev 118 inheritance abstract-class swift

我想用快速语言创建一个抽象函数.可能吗?

class BaseClass {
    func abstractFunction() {
        // How do I force this function to be overridden?
    }
}

class SubClass : BaseClass {
    override func abstractFunction() {
        // Override
    }
}
Run Code Online (Sandbox Code Playgroud)

jau*_*ard 186

Swift中没有抽象概念(如Objective-C),但你可以这样做:

class BaseClass {
    func abstractFunction() {
        preconditionFailure("This method must be overridden") 
    } 
}

class SubClass : BaseClass {
     override func abstractFunction() {
         // Override
     } 
}
Run Code Online (Sandbox Code Playgroud)

  • 或`fatalError("此方法必须被覆盖")` (17认同)
  • 或者你可以使用`assert(false,'这个方法必须被子类")"覆盖. (13认同)
  • 不鼓励使用例外.我宁愿使用断言或协议...... (8认同)
  • Swift中还有`preconditionFailure("Bla bla bla")`,它将在发布版本中执行,并且不需要返回语句.编辑:刚刚发现这个方法基本上等于`fatalError()`但它是更正确的方法(更好的文档,在Swift中引入的'precondition()`,`assert()`和`assertionFailure()`,阅读[这里](http://blog.krzyzanowskim.com/2015/03/09/swift-asserts-the-missing-manual/)) (5认同)
  • 当方法具有返回类型时,断言将需要return语句.我认为fatalError()更好的是这个原因 (4认同)
  • 如果函数有返回类型怎么办? (2认同)

Ste*_*cor 33

你想要的不是基类,而是协议.

protocol MyProtocol {
    func abstractFunction()
}

class MyClass : MyProtocol {
    func abstractFunction() {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你不在类中提供abstractFunction,那就是错误.

如果您还需要基类用于其他行为,则可以执行以下操作:

class MyClass : BaseClass, MyProtocol {
    func abstractFunction() {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不太奏效.如果BaseClass想要调用那些空函数,那么它还必须实现协议,然后实现这些函数.此外,子类仍然不会强制在编译时实现这些函数,并且您也不必强制执行该协议. (19认同)
  • 这就是我的观点.... BaseClass与协议无关,并且像抽象类一样,它应该与它有关.为了澄清我写的内容"如果BaseClass想要调用那些空函数,那么它还必须实现强制你实现函数的协议 - 然后导致Subclass不被强制在编译时实现函数,因为BaseClass已经完成了". (5认同)
  • 这实际上取决于你如何定义"抽象".抽象函数的重点在于,您可以将它放在可以执行普通类事务的类上.例如,我想要这个的原因是因为我需要定义一个静态成员,你似乎无法使用协议.因此,我很难看到这符合抽象函数的有用点. (4认同)
  • 我认为对上述评论的关注是,这不符合Liskov Substitution原则,该原则规定"程序中的对象应该可以替换为其子类型的实例,而不会改变该程序的正确性." 假设这是一个抽象类型.对于Factory Method模式,这一点尤其重要,其中基类负责创建和存储源自子类的属性. (3认同)
  • 抽象基类和协议不是一回事. (2认同)

Bob*_*son 29

我将一个支持抽象基类的平台的相当大量的代码移植到Swift并运行到很多.如果你真正想要的是抽象基类的功能,那么这意味着这个类既作为基于共享的类功能的实现(否则它只是一个接口/协议)并且它定义了必须由派生类.

要在Swift中执行此操作,您需要一个协议和一个基类.

protocol Thing
{
    func sharedFunction()
    func abstractFunction()
}

class BaseThing
{
    func sharedFunction()
    {
        println("All classes share this implementation")
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,基类实现了共享方法,但没有实现协议(因为它没有实现所有方法).

然后在派生类中:

class DerivedThing : BaseThing, Thing 
{
    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}
Run Code Online (Sandbox Code Playgroud)

派生类从基类继承sharedFunction,帮助它满足协议的这一部分,协议仍然要求派生类实现abstractFunction.

这种方法唯一真正的缺点是,由于基类没有实现协议,如果你有一个需要访问协议属性/方法的基类方法,你必须在派生类中重写它,并从那里调用基类(通过超级)传递,self以便基类具有用于执行其工作的协议的实例.

例如,假设需要调用abstractFunction的sharedFunction.协议将保​​持不变,类现在看起来像:

class BaseThing
{
    func sharedFunction(thing: Thing)
    {
        println("All classes share this implementation")
        thing.abstractFunction()
    }
}

class DerivedThing : BaseThing, Thing 
{
    func sharedFunction()
    {
        super.sharedFunction(self)
    }

    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在派生类的sharedFunction满足协议的那部分,但派生类仍然能够以一种相当简单的方式共享基类逻辑.

  • 对"基类没有实现协议"的理解和深度很好......这是一个抽象类的重点.我很困惑,这个基本的OO功能缺失了,但话说再说一遍,我是在Java上长大的. (4认同)
  • 然而,实现不允许无缝地实现模板函数方法,其中模板方法调用在子类中实现的大量抽象方法。在这种情况下,您应该将它们编写为超类中的普通方法、协议中的方法以及子类中的实现。在实践中,您必须写三遍相同的内容,并且仅依靠覆盖检查来确保不会出现任何灾难性的拼写错误!我真的希望现在 Swift 对开发人员开放,应该引入成熟的抽象函数。 (2认同)

jbo*_*boi 22

这个似乎是Apple在UIKit中处理抽象方法的"官方"方式.看看UITableViewController它和它的工作方式UITableViewDelegate.你要做的第一件事就是增加一条线:delegate = self.嗯,这正是诀窍.

1.将抽象方法放在协议中
protocol AbstractMethodsForClassX {
    func abstractMethod() -> String
}
Run Code Online (Sandbox Code Playgroud) 2.写你的基类
/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does)
/// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate`
class BaseClassX {
    var delegate: AbstractMethodsForClassX!

    func doSomethingWithAbstractMethod() -> String {
        return delegate.abstractMethod() + " - And I believe it"
    }
}
Run Code Online (Sandbox Code Playgroud) 3.编写子类.
/// First and only additional thing you have to do, you must set the "delegate" property
class ClassX: BaseClassX, AbstractMethodsForClassX {
    override init() {
        super.init()
        delegate = self
    }

    func abstractMethod() -> String {return "Yes, this works!"}
}
Run Code Online (Sandbox Code Playgroud) 这是,你如何使用这一切
let x = ClassX()
x.doSomethingWithAbstractMethod()
Run Code Online (Sandbox Code Playgroud)

检查Playground以查看输出.

一些备注

  • 首先,已经给出了很多答案.我希望有人能够一路找到这个.
  • 问题实际上是找到一个实现的模式:
    • 类调用一个方法,该方法必须在其派生的子类之一中实现(重写)
    • 在最好的情况下,如果未在子类中重写该方法,则在编译期间会出错
  • 关于抽象方法的事情是,它们是接口定义和基类中实际实现的一部分的混合.两者同时进行.由于迅捷是非常新的和非常清晰的定义,它没有这种方便,但"不洁"的概念(尚).
  • 对我来说(一个可怜的老Java家伙),这个问题时有发展.我已经阅读了这篇文章中的所有答案,这次我认为我发现了一种模式,看起来可行 - 至少对我而言.
  • 更新:看起来Apple的UIKit实施者使用相同的模式.UITableViewController实现UITableViewDelegate但仍需要通过明确设置delegate属性来注册为委托.
  • 这一切都在Xcode 7.3.1的Playground上进行了测试


har*_*n78 7

这样做的一种方法是使用在基类中定义的可选闭包,子窗口可以选择是否实现它.

class BaseClass {
    var abstractClosure?:(()->())?
    func someFunc()
    {
        if let abstractClosure=abstractClosure
        {
            abstractClosure()
        }
    } 
}

class SubClass : BaseClass {
    init()
    {
        super.init()
        abstractClosure={ ..... }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jor*_*tiz 6

好吧,我知道我迟到了比赛,并且我可能会利用已经发生的更改。对于那个很抱歉。

无论如何,我想贡献我的答案,因为我喜欢进行测试,而使用fatalError()isAFAIK 的解决方案是不可测试的,而带有例外的解决方案则很难进行测试。

我建议使用更快捷的方法。您的目标是定义一个具有一些通用细节但尚未完全定义的抽象,即抽象方法。使用协议定义抽象中所有预期的方法,既定义的方法,也定义未定义的方法。然后创建一个协议扩展,以实现您所定义的方法。最后,任何派生类都必须实现协议,这意味着所有方法,但是作为协议扩展一部分的方法已经实现了。

用一个具体功能扩展示例:

protocol BaseAbstraction {
    func abstractFunction() {
        // How do I force this function to be overridden?
    }
}

extension BaseAbstraction {
    func definedFunction() {
        print("Hello")
}

class SubClass : BaseAbstraction {
    func abstractFunction() {
        // No need to "Override". Just implement.
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,通过这样做,编译器再次成为您的朋友。如果该方法未“覆盖”,则您将在编译时收到错误,而不是fatalError()在运行时会收到的错误或异常。


Log*_*gan 5

我理解你现在在做什么,我认为你最好使用协议

protocol BaseProtocol {
    func abstractFunction()
}
Run Code Online (Sandbox Code Playgroud)

然后,您只需符合协议:

class SubClass : BaseProtocol {

    func abstractFunction() {
        // Override
        println("Override")
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的类也是子类,则协议遵循超类:

class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}
Run Code Online (Sandbox Code Playgroud)