Ruby 中的抽象方法和 NotImplementedError

主要观点:Ruby 的 NotImplementedError 异常常被用作抽象类中应被子类实现的方法的占位符,但这并非该异常类的预期用途。
关键信息:

  • 常见误用示例:在 BaseSetting 类中,to_html 方法在未被子类实现时抛出 NotImplementedErrorText 子类实现了该方法,而 Number 子类忘记实现。
  • 实际用途:当当前平台不支持某功能时会抛出该异常,如 JRuby 不支持 fork 时调用 Process.fork 会抛出该异常。
  • 避免使用的原因:其语义可能导致误解,如在 convert_to_html 方法中,rescue => e 不能捕获 NotImplementedError,因为它继承自 ScriptError 而非 StandardError
  • Python 的 NotImplementedError:在 Python 中该异常实际用于抽象方法,与 Ruby 不同。
  • 替代方法:

    • 提供默认实现:在基类中提供默认的 to_html 方法实现,避免抛出异常。
    • 明确抛出带消息:在抽象方法中明确抛出带有错误消息的异常,告知需要做什么来修复。
    • 创建自定义异常:定义继承自 StandardError 的自定义异常并抛出。
    • 抛出 NoMethodError:更接近表达类未响应某个方法的意思。
    • 编写测试:通过测试确保子类实现了特定方法,而不是依赖抽象方法抛出异常。
    • Sorbet:在复杂代码库中可使用 Sorbet 进行类型检查,它会告知哪些子类需要实现抽象方法。

    重要细节:

  • Ruby 的异常类继承关系:NotImplementedError 继承自 ScriptError,后者继承自 Exception,而 StandardError 不在此继承链中。
  • 不同框架的示例:如 ActiveRecord 从模型名推断表名,Hanami 框架中处理抽象方法的方式。
  • 相关更新:Michael Kohl 建议使用 SubclassResponsibility 作为抽象方法的异常名;Sorbet 内部在定义抽象方法时使用 NotImplementedError
阅读 9
0 条评论