协议之间的实现冲突
Implementation conflicts between protocols
我偶然发现了一个问题,我不知道该如何解决。
假设我们有一个基础 class(可能来自 FrameworkA),其中 属性 名为 subject
:
public class MyClass {
public var subject: String
}
我们有一个协议(可能来自 FrameworkB),还有另一个 属性 但同名:
public protocol MyProtocol {
var subject: String { get }
}
这两个属性代表完全不同的东西。
如何创建继承自 MyClass
并实现 MyProtocol
的 class?
我该如何使用这些属性?
public class SecondClass: MyClass, MyProtocol {
var MyProcotol.name: String { // <==== Obviously not allowed
return "something"
}
var MyClass.name: String { // <==== Obviously not allowed
return "something else"
}
}
我认为 C# 允许这样的声明,但我不是 100% 确定...
如果您可以控制此基础 class and/or 协议,您可以为属性指定唯一的名称,这样就可以解决问题。
如果您不能做到这一点,那么问题就变成了 SecondClass
是否真的必须自己履行这两个相互冲突的责任。具体来说,什么是MyProtocol
?一些委托协议?您可以让 SecondClass
出售一个符合该协议的单独对象,从而消除相互冲突的双重角色。
最重要的是,与其让单个对象尝试服务于两个相互冲突的目的,不如将责任分解为单独的对象来解决任何此类冲突。
好的,让我们暂时从使用这些 classes 的代码的角度来看问题,让我们忽略它们是如何实现的。
事实 1
如果 secondClass : SecondClass extends MyClass
那么我希望能够写:
secondClass.subject
事实 2
如果secondClass
符合MyProtocol
那么我希望能够写
secondClass.subject
如果我们为 secondClass
创建一种不同的方式来公开 MyClass.subject
和 MyProtocol.subject
,我们将打破面向对象的范式。
事实上
- 当您扩展 class 时,您隐式继承了所有非私有属性和方法,您不能(这是一件好事)重命名它们。
- 当您遵守协议时,您将完全按照协议中的描述公开所有非可选声明的属性和方法
如果 SecondClass
重命名伪代码中的 2 个属性,我们将无法编写这样的内容。
let list : [MyClass] = [MyClass(), SecondClass()]
for elm in list {
println(elm.subject)
}
可能的(部分)解决方案
您应该避免 is-a 方法,而应使用 has-a.
class SecondClass {
let myClass : MyClass
let somethingElse : MyProtocol
init(myClass : MyClass, somethingElse:MyProtocol) {
self.myClass = myClass
self.somethingElse = somethingElse
}
var myClassSubject : String { get { return myClass.subject } }
var myProtocolSubject : String { get { return somethingElse.subject } }
}
现在
SecondClass
不是一个MyClass
和
SecondClass
不是一个MyProtocol
它没有 subject
属性 消除任何混淆的风险。
希望这对您有所帮助。
我偶然发现了一个问题,我不知道该如何解决。
假设我们有一个基础 class(可能来自 FrameworkA),其中 属性 名为 subject
:
public class MyClass {
public var subject: String
}
我们有一个协议(可能来自 FrameworkB),还有另一个 属性 但同名:
public protocol MyProtocol {
var subject: String { get }
}
这两个属性代表完全不同的东西。
如何创建继承自 MyClass
并实现 MyProtocol
的 class?
我该如何使用这些属性?
public class SecondClass: MyClass, MyProtocol {
var MyProcotol.name: String { // <==== Obviously not allowed
return "something"
}
var MyClass.name: String { // <==== Obviously not allowed
return "something else"
}
}
我认为 C# 允许这样的声明,但我不是 100% 确定...
如果您可以控制此基础 class and/or 协议,您可以为属性指定唯一的名称,这样就可以解决问题。
如果您不能做到这一点,那么问题就变成了 SecondClass
是否真的必须自己履行这两个相互冲突的责任。具体来说,什么是MyProtocol
?一些委托协议?您可以让 SecondClass
出售一个符合该协议的单独对象,从而消除相互冲突的双重角色。
最重要的是,与其让单个对象尝试服务于两个相互冲突的目的,不如将责任分解为单独的对象来解决任何此类冲突。
好的,让我们暂时从使用这些 classes 的代码的角度来看问题,让我们忽略它们是如何实现的。
事实 1
如果 secondClass : SecondClass extends MyClass
那么我希望能够写:
secondClass.subject
事实 2
如果secondClass
符合MyProtocol
那么我希望能够写
secondClass.subject
如果我们为 secondClass
创建一种不同的方式来公开 MyClass.subject
和 MyProtocol.subject
,我们将打破面向对象的范式。
事实上
- 当您扩展 class 时,您隐式继承了所有非私有属性和方法,您不能(这是一件好事)重命名它们。
- 当您遵守协议时,您将完全按照协议中的描述公开所有非可选声明的属性和方法
如果 SecondClass
重命名伪代码中的 2 个属性,我们将无法编写这样的内容。
let list : [MyClass] = [MyClass(), SecondClass()]
for elm in list {
println(elm.subject)
}
可能的(部分)解决方案
您应该避免 is-a 方法,而应使用 has-a.
class SecondClass {
let myClass : MyClass
let somethingElse : MyProtocol
init(myClass : MyClass, somethingElse:MyProtocol) {
self.myClass = myClass
self.somethingElse = somethingElse
}
var myClassSubject : String { get { return myClass.subject } }
var myProtocolSubject : String { get { return somethingElse.subject } }
}
现在
SecondClass
不是一个MyClass
和SecondClass
不是一个MyProtocol
它没有 subject
属性 消除任何混淆的风险。
希望这对您有所帮助。