我有一个基类,它在一些数据结构中存储了很多其他数据对象,这个类通过一组add
/ remove
函数来管理我的集合中的那些数据对象。数据结构同步。
现在我去子类这个基类,子类就像基类一样,除了它对它将接受什么类型的数据对象有特殊规则(它查看数据对象上的值,并拒绝它们)如果值不对)。由于这种“有效性”检查,我为名为change
的子类创建了一个新函数。在change
函数中,它检查所有传入的数据对象并验证它们是否正常,并用这些数据对象替换数据结构中的所有数据对象。
问题是我不希望有人能够创建子类对象并允许它们调用基类add
/ remove
函数,因为我只希望子类是能够通过子类的change
函数进行更改。
我还没有找到一种在子类中“禁用”这些基类函数的好方法。我可以override
函数并实现空实现,但是调用者没有反馈该函数没有做任何事情。如果我使用类似fatalError
的东西,那么它不是编译时间,而是运行时。
我的其他想法是将基类的功能分解为多个协议,并将基类更改为简单地拥有所有数据结构,但是不符合任何协议,然后有多个子类,其中一个需要add
功能可以从基础继承,并且还符合add
协议,但不希望add
或remove
的协议可以从基础继承,并且只是不符合任何协议,而是创建自己的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
}
}
是否有更简单的方法来“隐藏”子类中的函数?
为了更好地解释我提出的解决方案,以及是否有更简单的方法来实现我当前的层次结构,这里的层次结构必须看起来像使用某些协议:
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") }
}
答案 0 :(得分:14)
协议版本可能是更好的设计 - 请参阅Leskov Substitution Principle数量您提到的其他内容。
您可以使用属性@available()
(请参阅Swift -> Language Reference -> Attributes)。
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()
您在child.doThat()
上收到以下错误消息:
'找时间做()'不可用:孩子不能这样做
然而,您可以通过执行以下操作来解决此问题(再次参见Liskov替换原则):
let maybeChild: Parent = Child()
maybeChild.doThis()
maybeChild.doThat()
答案 1 :(得分:4)
我使用@availability
处理此问题。类似的东西:
@available(*, deprecated=1.0, message="Do not call this method")
final func foo(){ //function you want to protect
}
只要您调用该函数,就会发出编译器警告。
有趣的是,将函数标记为unavailable
将引发编译器错误,如果有人调用此函数,则无法构建应用程序。不幸的是,没有办法在Swift中抑制这个错误,所以这也会为你的好用例打破它。也许你可以使用self.performSelector("foo")
来解决这个问题。
另请注意,我将foo()
标记为final
,这可以防止它被子类覆盖。
答案 2 :(得分:0)
您想要的是访问控制。 Swift的修饰符为internal
。 You can read more about it here in the docs under Access Control.
答案 3 :(得分:0)
我认为最明显的解决方案是:
只需将基类中的添加和删除功能设置为私有
class Parent {
func doThis() { print("Parent Did This") }
private func doThat() { print("Parent Did That") }
}
class Child: Parent {
override func doThis() {
print("Child Did This")
}
// This is a compile time error as the subclass will not be allowed to override this class, because it's private.
override func doThat() {
print("Not Supported")
return
}
}
在此示例中,重写doThat方法将导致编译时错误,因为不允许子类重写此方法,因为它是私有的。