ruby-on-rails - 单一职责原则——何时停止将代码提取到单独的类中

标签 ruby-on-rails ruby oop

我目前正在阅读“Rails AntiPatterns”,提到的第一个模式是单一职责原则。在这一点上,我遇到 SRP 的次数已经足够多了,我意识到它是像我这样的初学者需要理解的一个基本概念,这就是为什么它如此令人沮丧以至于它还没有点击。

书中给出了一个Order类的例子:

class Order < ActiveRecord::Base

    def self.find_purchase
    #...
    end

    def self.find_waiting_For_review
    #...
    end

    def self.find_waiting_for_sign_off
    #...
    end

    def self.advanced_search(fields, option = {})
    #...
    end

    def self.simple_search
    #...
    end

    def self.advanced_search
    #...
    end

    def to_xml
    #...
    end

    def to_json
    #...
    end

    def to_csv
    #...
    end

    def to_pdf
    #...
    end

end

为了说明 SRP,本书建议将 4 个实例方法提取到单独的 OrderConverter 类中。这对我来说很有意义。但与此同时,这个 OrderConverter 类仍然可能有多种更改原因:

  • 如果申请不再需要上述 4 种格式中的一种, 必须删除相应的方法。
  • 如果申请 需要转换成其他格式,需要更多的方法 实现的。
  • 如果用于将 Order 实例转换为不同格式的方法是 改变了(假设他们都使用相同的方法和不同的参数 对应于所需的格式)。

将这些方法中的每一个分离到一个单独的转换器类(即 PdfConverter、CsvConverter、XmlConverter 等)中不是更“正确”吗?这样,每个转换器类发生变化的唯一原因就是转换方法本身发生了变化。如果需要一种新格式,可以创建一个新类。如果不再需要旧格式,则可以简单地删除该类。原来的 Order 模型真的应该负责寻找它自己的实例吗?不能将“查找”方法分离到一个单独的“OrderFinder”类中吗?

我读过 Sandi Metz 的“Ruby 中的实用面向对象设计”的 SRP 章节,她建议进行以下测试以查看一个类是否具有单一职责:

How can you determine if the Gear class contains behavior that belongs somewhere else? One way is to pretend that it's sentient and to interrogate it. If you rephrase every one of its methods as a question, asking the question out to make sense. For example, "Please Mr. Gear, what is your ratio?" seems perfectly reasonable, while "Please Mr. Gear, what are your gear_inches?" is on shaky ground, and "Please Mr. Gear, what is your tire(size)?" is just downright ridiculous.

但极端一点,如果一个模型具有多个属性(即一辆汽车有多个门和一种颜色)以及相应的 attr_accessors,这是否已经违反了 SRP?难道每个新属性都不会为类更改添加另一个可能的原因吗?显然,答案不是将这些属性中的每一个都分离到单独的类中。那么,界限在哪里呢?

最佳答案

您写了有关 OrderConverter 类的内容,但没有显示该类的源代码。我假设此类包含方法 to_xml、to_json、to_csv 和 to_pdf。

Wouldn't it be even more "correct" to separate each of these methods into a separate converter class (i.e. PdfConverter, CsvConverter, XmlConverter, etc.)?

是的,将这些方法分离到转换器类可能是个好主意:每个转换器类将负责仅一种格式(一个责任)。

... if a model has more than one attribute (i.e. a car has a # of doors and a color) with corresponding attr_accessors, isn't this already a violation of SRP?

不,这些属性(如颜色、门的数量……)不是一组职责! Car 类的职责是描述一辆汽车(保存有关汽车的信息)。每个汽车实例将描述一辆汽车。例如,如果一辆汽车是一个模型类(假设你想在数据库中存储一辆汽车,而汽车的一个实例是数据库中的一行),那么如果你想改变 的方式,你必须改变汽车类在你的系统中描述一辆车

但是,如果一辆汽车定义了生产商,生产商将通过名称和地址进行描述,那么我会将生产商的详细信息提取到其他类中,因为这是描述汽车生产商的责任 car 而不是 Car 本身。

还有一件事。 SRP 不是一种模式。这是一个原则(首先在 SOLID 中)。该术语由 Robert Cecil Martin 引入。这里http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod您可以找到更多信息。

关于ruby-on-rails - 单一职责原则——何时停止将代码提取到单独的类中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19553369/

相关文章:

ruby-on-rails - 仅在更改密码设计注册时需要密码

php - 如何创建一个全局可访问的对象

ruby-on-rails - 如果尚未调用,则强制 Webmock stub_request 在测试结束时引发

ruby-on-rails - 开源新的遗物替代品

ruby-on-rails - 无方法错误 : undefined method `digest'

java - 在 Java 中保留泛型的封装

java - EE服务设计和OO建模

Mysql2::错误:不正确的字符串值 Rails 3 UTF8

ruby-on-rails - Rails 抛出 Redis::TimeoutError

ruby-on-rails - Rails ActiveRecord 创建或查找