协议之间的实现冲突

时间:2015-04-30 11:57:08

标签: swift oop inheritance protocols implementation

我偶然发现了一个问题,我无法弄清楚如何解决它。

假设我们有一个基类(可能来自FrameworkA),其属性名为subject

public class MyClass {
    public var subject: String
}

我们有一个协议(可能来自FrameworkB),另一个属性但具有相同的名称:

public protocol MyProtocol {
    var subject: String { get }
}

这两个属性代表完全不同的东西。

如何创建一个继承自MyClass并实现MyProtocol的类? 我该如何使用这些属性?

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%确定...

2 个答案:

答案 0 :(得分:3)

如果您可以控制此基类和/或协议,则可以为属性指定唯一名称并解决问题。

如果你不能这样做,问题就在于SecondClass是否真的必须履行这两个相互冲突的责任。具体来说,MyProtocol是什么?一些代表协议?您可以让SecondClass出售符合该协议的单独对象,从而消除冲突的双重角色。

底线,而不是让单个对象尝试服务于两个相互冲突的目的,将责任分成单独的对象来解决任何此类冲突。

答案 1 :(得分:1)

好的,暂时让我们从使用这些类的代码的角度来看问题,让我们忽略它们的实现方式。

事实1

如果 secondClass :SecondClass扩展MyClass,那么我希望能够写:

secondClass.subject

事实2

如果secondClass符合MyProtocol,那么我希望能够写出

secondClass.subject

如果我们为secondClass创建一种不同的方式来展示MyClass.subjectMyProtocol.subject,那么我们就打破了面向对象的范式。

逸岸

  1. 当你扩展一个类时,你隐式地继承了所有非私有属性和方法,你不能(并且这是一件好事)重命名它们。
  2. 当您遵守协议时,您将完全按照协议中的描述公开所有非可选的声明属性和方法
  3. 如果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
    3. subject 属性没有消除任何混淆的风险。

      希望这会有所帮助。