在Swift中,如何防止在子类上调用函数?

Tim*_*qua 6 inheritance ios swift

我有一个基类,它在一些数据结构中存储了很多其他数据对象,这个类通过一组add/ remove函数来管理我的集合中的那些数据对象,这些/ 函数使我的数据结构保持同步.

现在我去子类这个基类,子类就像基类一样,除了它对它将接受什么类型的数据对象有特殊规则(它查看数据对象上的值,如果值,则拒绝它们)不对.)由于这种"有效性"检查,我为被调用的子类创建了一个新函数change.在该change函数中,它检查所有传入的数据对象并验证它们是否正常,并用这些数据对象替换数据结构中的所有数据对象.

问题是我不希望有人能够创建子类对象并允许它们调用基类add/ remove函数,因为我只希望子类能够通过子类的change函数进行更改.

我还没有找到一种很好的方法来"禁用"子类中这些基类函数的使用.我可以override使用函数并实现空实现,但是没有反馈给调用者该函数没有做任何事情.如果我使用类似的东西fatalError,它不是编译时间,它是运行时.

我的另一个想法是将基类的功能分解为多个协议,并将基类更改为简单地拥有所有数据结构,但是不符合任何协议,然后有多个子类,其中需要该add功能的子类可以继承自基础并且另外符合add协议,但是不希望addremove可以从基础继承的协议,并且根本不符合任何协议,而是创建它们自己的change函数来修改数据结构.

这是一个更简单的层次结构来解释:

class Parent {

  func doThis() { print("Parent Did This") }
  func doThat() { print("Parent Did That") }

}

class Child: Parent {

  override func doThis() {
    print("Child Did This")
  }

  // I want this to be a compile time error
  override func doThat() {
    print("Not Supported")
    return
  }

}
Run Code Online (Sandbox Code Playgroud)

有没有更简单的方法来"隐藏"子类中的函数?

编辑1

为了更好地解释我提出的解决方案,以及是否有更简单的方法来实现我当前的层次结构,这里的层次结构必须看起来像使用某些协议:

protocol CanDoThis {
  func doThis()
}

protocol CanDoThat {
  func doThat()
}

class Parent {
  // Important properties that all children should have
  var property1: Int = 0
  var property2: String = ""
}

class Child1: Parent, CanDoThis {
  func doThis() { print("Child1 Can Do This") }
}

class Child2: Parent, CanDoThat {
  func doThat() { print("Child2 Can Do That") }
}

class Child3: Parent, CanDoThis, CanDoThat {
  func doThis() { print("Child3 Can Do This") }
  func doThat() { print("Child3 Can Do That") }
}
Run Code Online (Sandbox Code Playgroud)

Kev*_*vin 15

放弃

协议版本可能是更好的设计 - 参见莱斯科夫替代原则数额你提到的其他事情.

回答这个问题

您可以使用该属性@available()(请参阅Swift - >语言参考 - >属性).

class Parent {
    func doThis() { print("Parent Did This") }
    func doThat() { print("Parent Did That") }
}

class Child: Parent {
    override func doThis() {
        print("Child Did This")
    }

    @available(*, unavailable, message:"Child can't doThat")
    override func doThat() {
        print("Not Supported")
    }
}


let parent = Parent()
parent.doThis()
parent.doThat()

let child = Child()
child.doThis()
child.doThat()
Run Code Online (Sandbox Code Playgroud)

您收到以下错误消息child.doThat():

'doThat()'不可用:孩子不能这样做

但是,您可以通过执行以下操作来解决此问题(再次参见Liskov替换原则):

let maybeChild: Parent = Child()
maybeChild.doThis()
maybeChild.doThat()
Run Code Online (Sandbox Code Playgroud)


Nic*_*ick 5

我会使用 来处理这个问题@availability。就像是:

@available(*, deprecated=1.0, message="Do not call this method")
final func foo(){ //function you want to protect
}
Run Code Online (Sandbox Code Playgroud)

每当您调用该函数时,都会向您发出编译器警告。

有趣的是,将函数标记为unavailable会引发编译器错误,如果有人调用此函数,则无法构建应用程序。不幸的是,在 Swift 中没有办法抑制这个错误,所以这也会破坏你的良好用例。也许你可以通过使用来解决这个问题self.performSelector("foo")

另请注意,我标记foo()final,这可以防止它被子类覆盖。