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

时间:2017-11-11 23:16:13

标签: ios swift inheritance swift-protocols

所以我是iOS开发的新手,并且在我的实习中对应用程序进行了一些小的更改,这个实例具有相对较大的Objective-c代码库。我一直在树屋学习(哇,爱他们!),我刚刚学习了协议。目前,它们应该在某些情况下使用,教师使用这个例子。

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

3 个答案:

答案 0 :(得分:3)

您正在寻找的是抽象类抽象类的目的是作为继承的具体类的基类,但是不能直接实例化抽象类。

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

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

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

您可以通过提供一个方法的实现来提供类似的类,如果它没有被子类覆盖,则该方法会抛出异常。这会产生运行时错误而不是编译时错误。

e.g。

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()
     }
 }

答案 1 :(得分:1)

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

protocol YourProtocol {
  func pay()
}

class Employee: YourProtocol {
  func pay() {
     fatalError("Must Override")
  }
}

class SubEmployee: Employee {
  func pay() {
     print("stuff here")
  }
}

答案 2 :(得分:0)

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

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#>)
    }
}