私は現在「Rails AntiPatterns」を読んでおり、言及された最初のパターンの 1 つは単一責任の原則です。この時点で、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 モデルは、それ自体のインスタンスを見つける責任を本当に負うべきでしょうか? 「find」メソッドを別の「OrderFinder」クラスに分離できませんでしたか?
私は Sandi Metz の「Practical Object-Oriented Design In Ruby」の SRP の章を読みました。彼女は、クラスが単一の責任を持っているかどうかを確認するために次のテストを推奨しています。
Gear クラスに別の場所に属する動作が含まれているかどうかを判断するにはどうすればよいでしょうか? ひとつの方法は、それが感覚を持っているふりをして尋問することです。そのメソッドのすべてを質問として言い換えると、質問が意味をなすようになります。たとえば、「ギアさん、あなたの比率は?」「ギアさん、あなたのギアのインチ数は?」不安定な地面にいて、「ギアさん、タイヤ(サイズ)は何ですか?」まったくばかげている。
しかし、極端に言えば、モデルに複数の属性 (つまり、車にドアの数と色がある) と対応する attr_accessors がある場合、これはすでに SRP に違反しているのではないでしょうか? 新しい属性ごとに、クラスが変更される別の理由が追加されることはありませんか? 明らかに、答えは、これらの各属性を個別のクラスに分離することではありません。では、どこに線を引くのでしょうか?