将协议添加到超类,这将强制从它继承的其他类实现协议



所以我是iOS开发的新手,在我的实习期间一直在对一个具有相对较大objective-c代码库的应用程序进行微小的更改。我一直在从Treehouse学习快速(哇,爱他们!),我刚刚了解了协议。目前,它们应该在某些情况下使用,教师使用了此示例。

假设您有一家公司,有两种不同类型的员工:薪水和小时(很常见)。现在,它们都将从一个名为 Employee 的超类继承,并且都必须调用一个名为"pay"的函数来支付员工。如何强制实施这些类来实现该函数?当然,使用协议,但这需要您记住将其添加到函数声明中。有没有办法将协议添加到超类"Employee"中,然后从该类继承的任何内容都必须遵循该超类的协议。有没有其他方法可以做到这一点?谢谢!

你要找的是一个抽象类。 抽象类的目的是充当要从中继承的具体类的基类,但抽象不能直接实例化。

如果Employee是一个抽象类,那么任何实际实例化Employee实例的尝试都将被编译器报告为错误。 你需要实例化一个具体的Employee子类,例如SalariedEmployeeHourlyEmployee

Employee类的定义将包括需要calculatePay方法,如果具体子类未实现该方法,则再次发生编译时错误。

现在,坏消息。 Objective-C 和 Swift 都不支持抽象类。

可以通过提供方法的实现来提供类似的类,如果该方法未被子类重写,则会引发异常。 这会产生运行时错误,而不是编译时错误。

例如

class Employee {
var givenName: String
var surname: String
...
init(givenName: String, surname: String) {
self.givenName = givenName
self.surname = surname
}
func calculatePay() -> Float {
fatalError("Subclasses must override calculatePay")
}
}

class SalariedEmployee: Employee {
var salary: Float
init(givenName: String, surname: String, annualSalary: Float) {
salary = annualSalary
super.init(givenName: givenName, surname: surname)
}
override func calculatePay() -> Float {
return salary/12     // Note: No call to super.calculatePay
}
}

无论calculatePay是基类的一部分,还是通过向协议添加一致性的扩展分配给基类,结果都是相同的;

  • Employee类将需要生成某种错误的函数的默认实现
  • 子类实现该方法失败不会导致编译时错误

你可以单独为每个子类分配一个协议,比如Payable,但是由于协议不是基类的一部分,你不能这样说:

var employees[Employee]
for e in employees {
let pay = e.calculatePay()
}

您将不得不使用稍微复杂的:

for e in employees {
if e is Payable {
let pay = e.calculatePay()
}
}

不幸的是,尚不支持abstract函数。一种可能的解决方法是在子类未覆盖此类函数时启动fatalError,这样做:

protocol YourProtocol {
func pay()
}
class Employee: YourProtocol {
func pay() {
fatalError("Must Override")
}
}
class SubEmployee: Employee {
func pay() {
print("stuff here")
}
}

我的方法是将委托作为参数包含在类初始值设定项中。 请参阅下面的代码:

protocol ProtocolExample {
func somethingNeedsToHappen()
}
// typical class example with delegate property for the required protocol
class ClassExampleA {

var delegate: ProtocolExample!

init() {
}

func aCriticalMethodWithUpdates() {
delegate.somethingNeedsToHappen()
}
}
// use class example in a view controller.  Can easily forget to invoke the delegate and protocol
class MySampleViewControllerA: UIViewController {

var classExampleA : ClassExampleA!

func loadMyData() {
classExampleA = ClassExampleA()
}
}
// an alternative approach for the class is to include the delegate parameter in the initializer.
class ClassExampleB {

var delegate: ProtocolExample!

init(delegateForUpdates: ProtocolExample) {
delegate = delegateForUpdates
}

func doSomething() {
delegate.somethingNeedsToHappen()
}
}
// go to use it and you're reminded that the parameter is required...
class MySampleViewControllerB: UIViewController {

var classExampleB: ClassExampleB!

func loadMyData() {
classExampleB = ClassExampleB() // error: Missing argument for parameter 'delegateForUpdates' in call
}
}
// so to avoid error:
class MySampleViewControllerC: UIViewController {

var classExampleB: ClassExampleB!

func loadMyData() {
classExampleB = ClassExampleB(delegateForUpdates: <#ProtocolExample#>)
}
}

最新更新