【问题标题】:Swift - mixing abstract and concrete methodsSwift - 混合抽象和具体方法
【发布时间】:2015-08-14 23:17:26
【问题描述】:

Swift 没有抽象类和方法。相反,它提供协议。

当您的类是完全抽象的或完全具体的时,这很好。

但是,实现具有具体方法的抽象类的最佳“Swift”方式是什么?

伪代码示例:

class Animal {
  abstract makeSound()
  abstract eyeCount()
}

class Mammal : Animal {
  override eyeCount { return 2 } // Let's assume all mammals have hard-coded 2 eyes...

class Cat : Mammal {
  override makeSound { print "Meow!" }
}

class Dog : Mammal {
  override makeSound { print "Woof!" }
}

在哺乳动物中,我确实想实现具体方法 eyeCount(),因为所有哺乳动物都有 2 只硬编码的眼睛(据说),我不想在狗和猫中重新实现它。但是,makeSound() 应该只用于 Dog 和 Cat,因为哺乳动物有不同的声音。

您将如何在 Swift 中实现这一点?谢谢!

【问题讨论】:

    标签: ios swift oop abstract-class


    【解决方案1】:

    执行此操作的常用方法是创建一个包含具体方法的抽象类。所有类都可以继承这个抽象类来继承具体方法和抽象方法。

    UIGuestureRecognizerUIGuestureRecognizerSubclass 就是一个很好的例子。因为这是为了子类化,所以这个抽象类包含许多内部具体方法以及可子类化的抽象方法供您实现。

    这是许多 Swift 和 Objective-C 项目的常见模式。

    【讨论】:

    • 我尝试在 Swift 中做类似的事情。但是,我在“我的 UIGestureRecgonizerSubclass”上遇到了编译器错误,因为它没有实现在“我的 UIGestureRecognizer”协议中声明的(必需的)方法。
    • 如果您决定遵循协议,则必须实现所需的方法,除非这些方法是@optional
    • 你是对的。然而,我确实希望避免实现协议中的可选方法实现的具体“叶”类。这将导致“respondToSelector”调用——在我看来,这是一种代码恐怖。
    【解决方案2】:

    正如@BobDickinson 在Abstract functions in Swift Language 中所建议的那样,您可以这样做的一种方法如下:

    protocol Animal {
        var eyeCount: Int { get }
        func makeSound()
    }
    
    // Note - `Mammal` doesn't conform to `Animal`.
    class Mammal {
        let eyeCount = 2
    }
    
    // Only `Cat` and `Dog` conform to `Animal`, so only they need to implement `makeSound`.
    class Dog: Mammal, Animal {
        func makeSound() {
            println("Woof")
        }
    }
    
    class Cat: Mammal, Animal {
        func makeSound() {
            println("Meow")
        }
    }
    

    【讨论】:

    • 这是一个不错的解决方案。但是,我宁愿避免分别继承 Mammal 和 Animal。 Mammal 是 Animal,因此 Mammal 的每个子类也应该实现 Animal。
    • 另外,为了抽象起见,我们假设 eyeCount 是一个函数,而不是一个带有 getter 的属性。这是一个糟糕的例子。
    【解决方案3】:

    我会这样实现它:

    class AbstractAnimal
    {
        // Fully abstract method
        func methodThatReturnsSomething() -> String  {
            fatalError("methodThatReturnsSomething() is abstract and must be overriden!");
        }
    
        func eyeCount() -> Int {
            return 2;
        }
    }
    

    fatalError 防止 Xcode 抱怨抽象方法 methodThatReturnsSomething() 实际上没有返回任何东西。

    【讨论】:

    • 我真的很难处理那些声明只会在运行时出错的事情。它使代码不可靠。检查@pommes 答案或这个答案,以获得在编译时检查的实现stackoverflow.com/a/39038828/2435872
    【解决方案4】:

    您可以使用 Protocol Extensions 获得与 Abstract Classes 完全相同的行为:在编译时检查抽象方法是否在子类中实现。

    protocol Entity {
      // MARK: - Abstract methods
      func filename() -> String
    
      // MARK: - Traits
      func saveData(data: NSArray)
    }
    
    extension Entity {
      func saveData(data: NSArray) {
          // Do something and call:
          let filename = filename()
      }
    }
    

    现在您可以在子类上实现Entity 协议,编译器将强制您实现filename(),而saveData() 方法已经实现。

    【讨论】:

    • 很好,但是在抽象类中我可以定义变量并在函数中使用它们。在这里,我必须在实现协议的每个类中声明变量,并通过访问器方法从扩展访问它们,还是有更好的方法?
    • 扩展不能有存储的属性,所以这种方法相当有限。
    猜你喜欢
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 2016-08-13
    • 1970-01-01
    • 2020-08-26
    相关资源
    最近更新 更多