协议之间的实现冲突

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.subjectMyProtocol.subject,我们将打破面向对象的范式。

事实上

  1. 当您扩展 class 时,您隐式继承了所有非私有属性和方法,您不能(这是一件好事)重命名它们。
  2. 当您遵守协议时,您将完全按照协议中的描述公开所有非可选声明的属性和方法

如果 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 } }
}

现在

  1. SecondClass 不是一个MyClass
  2. SecondClass 不是一个MyProtocol

它没有 subject 属性 消除任何混淆的风险。

希望这对您有所帮助。