我正在阅读“rails反模式”,其中提到的第一个模式是单一责任原则。在这一点上,我已经多次遇到srp,意识到这是一个基本的概念,像我这样的初学者理解,这就是为什么它是如此令人沮丧,它还没有点击。
这本书举了一个订单类的例子:
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种格式之一,
必须删除相应的方法。
如果申请
需要转换成其他格式,需要更多的方法
实施。
如果用于将订单实例转换为不同格式的方法是
已更改(假设它们都使用相同的方法和不同的参数
与所需格式相对应)。
把这些方法分成一个单独的转换器类(如pdfconverter、csvconverter、xmlconverter等)是不是更“正确”?这样,每个转换器类更改的唯一原因就是转换方法本身发生了更改。如果需要新格式,则可以创建新类。如果不再需要旧格式,则可以简单地删除该类。原始的订单模型真的应该负责寻找自己的实例吗?你不能把“find”方法分成一个单独的“orderfinder”类吗?
我已经阅读了s and i metz的“ruby中面向对象的实用设计”的srp一章,她建议进行以下测试,看看一个类是否有单一的职责:
如何确定gear类是否包含属于某个地方的行为
还有吗?一种方法是假装它有知觉并审问它。如果你
把它的每一种方法重新表述为一个问题,提出问题
感觉。例如,“请盖尔先生,您的比率是多少?”看起来很完美
合理,而“请齿轮先生,您的齿轮是多少英寸?”摇摇欲坠
地面,还有“请盖尔先生,您的轮胎(尺寸)是多少?”完全正确
荒谬的
但是,如果一个模型有一个以上的属性(即一辆车有一个门和一个颜色)和相应的属性访问器,这不是已经违反了srp吗?每一个新属性是否都为类的更改添加了另一个可能的原因?显然,答案不是将这些属性中的每一个分离为单独的类。那么我们在哪里划清界限呢?
最佳答案
你写的是OrderConverter
类,但没有显示该类的源代码。我假设这个类包含到XML、到JSON、到CSV和到PDF的方法。
把这些方法分成一个单独的转换器类(如pdfconverter、csvconverter、xmlconverter等)是不是更“正确”?
是的,将这些方法分离到转换器类是一个很好的主意:每个转换器类只负责一种格式(一种责任)。
…如果一个模型有多个属性(即一辆车有一个门和一个颜色)和相应的属性访问器,这不是已经违反了srp吗?
不,这些属性(比如颜色,门的编号,…)不是一组责任!类的职责是描述一辆车(保存关于一辆车的信息)。每个汽车实例将描述一辆汽车。例如,如果汽车是一个模型类(假设您想将汽车存储在db中,汽车的一个实例是db中的一行),那么如果您想更改系统中描述汽车的方式,则必须更改汽车类。
但是如果一辆车已经定义了一个生产者,生产者将被描述为名字和地址,那么我将把生产者的细节提取到其他类中,因为这是描述一辆车的生产者的责任,而不是描述一辆车本身。
还有一件事。SRP不是一种模式。这是一条原则(第一条是实实在在的)。这个词是由罗伯特·塞西尔·马丁提出的。在这里你可以找到更多的信息。
关于ruby-on-rails - 单一责任原则-何时停止将代码提取到单独的类中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19553369/