Swift语言中的抽象类
有没有办法在Swift语言创build一个抽象类,或者这是一个像Objective-C的限制? 我想创build一个类似于Java定义为抽象类的抽象类。
Swift中没有抽象类(就像Objective-C一样)。 你最好的select是使用一个协议 ,就像一个Java接口。
使用Swift 2.0,您可以使用协议扩展添加方法实现和计算属性实现。 你唯一的限制是你不能提供成员variables或常量 , 也没有dynamic分派 。
这种技术的一个例子是:
protocol Employee { var annualSalary: Int {get} } extension Employee { var biweeklySalary: Int { return self.annualSalary / 26 } func logSalary() { print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly") } } struct SoftwareEngineer: Employee { var annualSalary: Int func logSalary() { print("overridden") } } let sarah = SoftwareEngineer(annualSalary: 100000) sarah.logSalary() // prints: overridden (sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly
请注意,即使对于结构体,它也提供了“抽象类”的特征,但类也可以实现相同的协议。
另请注意,实现Employee协议的每个类或结构都必须再次声明annualSalary属性。
最重要的是,请注意, 没有dynamic调度 。 当存储为SoftwareEngineer
的实例上调用logSalary
,将调用该方法的重写版本。 当实例调用logSalary
后,调用原始实现(即使实例实际上是Software Engineer
它也不会dynamic分派到被覆盖的版本。
有关更多信息,请查看有关该function的伟大WWDCvideo: 使用Swift中的值types构build更好的应用程序
请注意,这个答案是针对Swift 2.0及以上
您可以通过协议和协议扩展实现相同的行为。
首先,编写一个协议,充当所有必须在所有符合它的types中实现的方法的接口。
protocol Drivable { var speed: Float { get set } }
然后,您可以将默认行为添加到符合它的所有types
extension Drivable { func accelerate(by: Float) { speed += by } }
现在可以通过实施Drivable
来创build新的types。
struct Car: Drivable { var speed: Float = 0.0 init() {} } let c = Car() c.accelerate(10)
所以基本上你会得到:
- 编译时间检查,确保所有
Drivable
实现speed
- 您可以实施符合
Drivable
(accelerate
)的所有types的默认行为 -
Drivable
保证不被实例化,因为它只是一个协议
这个模型实际上performance得更像特征,意味着你可以遵循多个协议,并采取其中任何一个的默认实现,而对于抽象的超类,你仅限于一个简单的类层次结构。
我认为这是最接近Java的abstract
或C#的abstract
:
class AbstractClass { private init() { } }
请注意,为了使private
修饰符正常工作,您必须在单独的Swift文件中定义此类。
编辑:仍然,这个代码不允许声明一个抽象的方法,从而强制其实施。
在我挣扎了好几个星期之后,我终于意识到如何将Java / PHP抽象类翻译成Swift:
public class AbstractClass: NSObject { internal override init(){} public func getFoodToEat()->String { if(self._iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } internal func _iAmHungry()->Bool { fatalError(__FUNCTION__ + "Must be overridden"); return false; } } public class ConcreteClass: AbstractClass, IConcreteClass { private var _hungry: Bool = false; public override init() { super.init(); } public func starve()->Void { self._hungry = true; } public override func _iAmHungry()->Bool { return self._hungry; } } public protocol IConcreteClass { func _iAmHungry()->Bool; } class ConcreteClassTest: XCTestCase { func testExample() { var concreteClass: ConcreteClass = ConcreteClass(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.starve(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } }
不过,我认为苹果没有实现抽象类,因为它通常使用委托+协议模式。 例如,上面的相同的模式会更好地完成这样的事情:
import UIKit public class GoldenSpoonChild { private var delegate: IStomach!; internal init(){} internal func setup(delegate: IStomach) { self.delegate = delegate; } public func getFoodToEat()->String { if(self.delegate.iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } } public class Mother: GoldenSpoonChild, IStomach { private var _hungry: Bool = false; public override init() { super.init(); super.setup(self); } public func makeFamilyHungry()->Void { self._hungry = true; } public func iAmHungry()->Bool { return self._hungry; } } protocol IStomach { func iAmHungry()->Bool; } class DelegateTest: XCTestCase { func testGetFood() { var concreteClass: Mother = Mother(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.makeFamilyHungry(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } }
我需要这种模式,因为我想在UITableViewController中通用一些方法,如viewWillAppear等。
有一种使用协议来模拟抽象类的方法。 这是一个例子:
protocol MyProtocol { func doIt() } class BaseClass { var myDelegate: MyProtocol! init() { ... } func myFunc() { ... self.myDelegate.doIt() ... } } class ChildClass: BaseClass, MyProtocol { override init(){ super.init() self.myDelegate = self } func doIt() { // Custom implementation } }
最简单的方法是在协议扩展中使用对fatalError("Not Implemented")
的抽象方法(而不是variables)的调用。
protocol MyInterface { func myMethod() -> String } extension MyInterface { func myMethod() -> String { fatalError("Not Implemented") } } class MyConcreteClass: MyInterface { func myMethod() -> String { return "The output" } } MyConcreteClass().myMethod()
如何实现抽象类的另一种方法是阻止初始化器。 我这样做了:
class Element:CALayer { // IT'S ABSTRACT CLASS override init(){ super.init() if self.dynamicType === Element.self { fatalError("Element is abstract class, do not try to create instance of this class") } } }
我试图做一个Weather
抽象类,但是使用协议并不理想,因为我不得不一遍又一遍地写同样的init
方法。 扩展协议和写一个init
方法有问题,特别是因为我使用符合NSCoding
NSObject
。
所以我想出了NSCoding
一致性:
required init?(coder aDecoder: NSCoder) { guard type(of: self) != Weather.self else { fatalError("<Weather> This is an abstract class. Use a subclass of `Weather`.") } // Initialize... }
至于init
:
fileprivate init(param: Any...) { // Initialize }