Swift语言中的抽象函数
我想用迅捷的语言创build一个抽象函数。 可能吗?
class BaseClass { func abstractFunction() { // How do I force this function to be overridden? } } class SubClass : BaseClass { override func abstractFunction() { // Override } }
在Swift中没有抽象的概念(像Objective-C),但你可以这样做:
class BaseClass { func abstractFunction() { preconditionFailure("This method must be overridden") } } class SubClass : BaseClass { override func abstractFunction() { // Override } }
你想要的不是一个基类,而是一个协议。
protocol MyProtocol { func abstractFunction() } class MyClass : MyProtocol { func abstractFunction() { } }
如果你没有在你的类中提供abstractFunction,那是错误的。
如果你仍然需要其他行为的基类,你可以这样做:
class MyClass : BaseClass, MyProtocol { func abstractFunction() { } }
我从一个支持抽象基类到Swift的平台移植了大量的代码,并运行到这个很多。 如果你真正想要的是抽象基类的function,那就意味着这个类既可以作为基于共享的类function的实现(否则它只是一个接口/协议),它定义了必须实现的方法派生类。
要在Swift中做到这一点,你需要一个协议和一个基类。
protocol Thing { func sharedFunction() func abstractFunction() } class BaseThing { func sharedFunction() { println("All classes share this implementation") } }
请注意,基类实现共享方法,但不实现协议(因为它不实现所有的方法)。
然后在派生类中:
class DerivedThing : BaseThing, Thing { func abstractFunction() { println("Derived classes implement this"); } }
派生类从基类inheritancesharedFunction,帮助它满足协议的这一部分,协议仍然需要派生类来实现abstractFunction。
这种方法唯一的缺点是,由于基类没有实现协议,如果你有一个需要访问协议属性/方法的基类方法,你将不得不在派生类中覆盖它,并从那里调用基类(通过super)传递self
以便基类有一个协议的实例来完成它的工作。
例如,可以说sharedFunction需要调用abstractFunction。 该协议将保持不变,现在类将如下所示:
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"); } }
现在来自派生类的sharedFunction满足协议的这一部分,但派生类仍然能够以合理直接的方式共享基类逻辑。
这似乎是苹果如何在UIKit中处理抽象方法的“官方”方式。 看一看UITableViewController
和UITableViewController
的工作方式。 你做的第一件事就是添加一行: delegate = self
。 那么,这正是诀窍。
1.将抽象方法放入协议中
protocol AbstractMethodsForClassX { func abstractMethod() -> String }
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" } }
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!"} }
这里是,如何使用这一切
let x = ClassX() x.doSomethingWithAbstractMethod()
查看Playground以查看输出。
一些备注
- 首先,已经有很多答案。 我希望有人find这一个。
- 问题实际上是要find一个模式来实现:
- 一个类调用一个方法,该方法必须在其派生的子类之一中实现(重写)
- 在最好的情况下,如果方法在子类中没有被覆盖,那么在编译期间得到一个错误
- 关于抽象方法的事情是,它们是接口定义和基类中实际实现的一部分的混合体。 两者同时。 由于迅捷是非常新的和非常清晰的界定,它没有这样的快速,但“不洁”的概念(还)。
- 对我来说(一个可怜的老Java家伙),这个问题不时演变。 我已经阅读了这篇文章中的所有答案,这一次我想我find了一个模式,看起来是可行的 – 至less对我来说。
- 更新 :看起来苹果的UIKit实现者使用相同的模式。
UITableViewController
实现UITableViewDelegate
但仍需要注册为委托,通过明确设置delegate
属性。 - 这一切都在Xcode 7.3.1的Playground上进行testing
我明白你现在在做什么,我想你最好使用一个协议
protocol BaseProtocol { func abstractFunction() }
那么,你只要遵守协议:
class SubClass : BaseProtocol { func abstractFunction() { // Override println("Override") } }
如果你的类也是一个子类,那么协议遵循超类:
class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}
这样做的一个方法是使用在基类中定义的可选闭包,孩子可以select是否实现它。
class BaseClass { var abstractClosure?:(()->())? func someFunc() { if let abstractClosure=abstractClosure { abstractClosure() } } } class SubClass : BaseClass { init() { super.init() abstractClosure={ ..... } } }
使用assert
关键字来执行抽象方法:
class Abstract { func doWork() { assert(false, "This method must be overriden by the subclass") } } class Concrete : Abstract { override func doWork() { println("Did some work!") } } let abstract = Abstract() let concrete = Concrete() abstract.doWork() // fails concrete.doWork() // OK
不过, Steve Waddicor提到你可能需要一个protocol
。
那么,我知道我迟到了,我可能正在利用已经发生的变化。 对于那个很抱歉。
无论如何,我想提供我的答案,因为我喜欢做testing, fatalError()
的解决scheme是AFAIK,不可testing,有例外的testing更难testing。
我会build议使用更快速的方法。 你的目标是定义一个具有一些共同细节的抽象,但是没有完全定义,即抽象方法。 使用一个定义抽象中所有预期方法的协议,既定义的方法,也定义那些不是。 然后创build一个协议扩展,实现在你的情况下定义的方法。 最后,任何派生类必须实现协议,这意味着所有的方法,但是协议扩展的一部分已经有了它们的实现。
用一个具体的函数扩展你的例子:
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. } }
请注意,通过这样做,编译器又是你的朋友。 如果方法没有被“覆盖”,那么在编译时你将会得到一个错误,而不是你在fatalError()
得到的错误或者在运行时会发生的exception。
我不知道会不会有用,但是在尝试构buildSpritKit游戏时,我也遇到了与抽象方法类似的问题。 我想要的是一个抽象的动物类,它有诸如move(),run()等方法,但是精灵名字(和其他function)应该由类的子类提供。 所以我最终做了这样的事情(Swift 2testing):
import SpriteKit // --- Functions that must be implemented by child of Animal public protocol InheritedAnimal { func walkSpriteNames() -> [String] func runSpriteNames() -> [String] } // --- Abstract animal public class Animal: SKNode { private let inheritedAnimal: InheritedAnimal public init(inheritedAnimal: InheritedAnimal) { self.inheritedAnimal = inheritedAnimal super.init() } public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public func walk() { let sprites = inheritedAnimal.walkSpriteNames() // create animation with walking sprites... } public func run() { let sprites = inheritedAnimal.runSpriteNames() // create animation with running sprites } } // --- Sheep public class SheepAnimal: Animal { public required init?(coder aDecoder: NSCoder) { fatalError("NSCoding not supported") } public required init() { super.init(inheritedAnimal: InheritedAnimalImpl()) } private class InheritedAnimalImpl: InheritedAnimal { init() {} func walkSpriteNames() -> [String] { return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"] } func runSpriteNames() -> [String] { return ["sheep_run_01", "sheep_run_02"] } } }
我理解这个问题,并正在寻找相同的解决scheme。 协议与抽象方法不一样。
在协议中,你需要指定你的类符合这样的协议,抽象方法意味着你必须重写这种方法。
换句话说,协议是可选的,你需要指定基类和协议,如果你不指定协议,那么你不必重写这样的方法。
抽象方法意味着你想要一个基类,但是需要实现你自己的方法,或者两个不相同的方法。
我需要同样的行为,这就是为什么我正在寻找一个解决scheme。 我猜Swift是缺less这样的function。
这个问题还有另外一个select,虽然与@ jaumard的build议相比还是有不足的地方。 它需要一个返回语句。 虽然我错过了要求它的观点,因为它直接抛出exception:
class AbstractMethodException : NSException { init() { super.init( name: "Called an abstract method", reason: "All abstract methods must be overriden by subclasses", userInfo: nil ); } }
接着:
class BaseClass { func abstractFunction() { AbstractMethodException.raise(); } }
无论发生什么事情都是无法达到的,所以我不明白为什么要强制回报。