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

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

public class MyClass {
    public var subject: String
}

我们有一个协议(protocol)(可能来自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%...

最佳答案

好的,让我们从使用这些类的代码的 Angular 来看一下问题,而忽略它们的实现方式。

事实1

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

secondClass.subject

事实2

如果secondClass符合MyProtocol,那么我希望能够编写
secondClass.subject

如果我们为secondClass创建一种不同的方式来公开MyClass.subjectMyProtocol.subject,那么我们将打破面向对象范例。

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

    如果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 属性可消除任何混淆风险。

    希望这可以帮助。

    08-04 20:52