はじめに
クラス設計の有名な原則としてSRP(The Single Responsibility Principle)があります。これについてまとめる機会があったので、ついでに公開します。
この記事は"Agile Principles, Patterns, and Practices in C#"を基にまとめています。
スライド
このスライドにまとめてあるので見ればなんとなくはわかると思います。ただ、口頭発表用で作ったのでスライドには書いてないこともいくつかありますので、その辺はこの記事の文を見てください。
SRPとは
日本語では単一責任の原則と言われます。
この原則が示す最も大事なことは、クラスが変更される理由は唯一ということであるということです。これを言い換えると、1つのクラスは1つの責任しか持たないということになります。
もし1つのクラスが複数の責任を持つとお互いの責任が結びつき、1つの責任に対する変更が他の責任に影響してしまいます。これは予期しない動作や整合性の取れない設計に繋がるため、避けるべきです。もしこのような設計があった場合には責任をそれぞれ独立したクラスに分けることで解決することができます。
ただし、複数の責任があっても良い場合があります。それはお互いの責任が影響し合わず、分けてしまうことにより複雑さを生みだす場合です。
SRP違反
フォントが好きなのでフォントに関する例で説明します。
上の図のGlyph(フォントのひとつひとつの文字を表す)クラスはペイントアプリからは描画を求められ、フォントエディタからは計算(変形)を求められます。
この状態はGlyphクラスに描画の責任と計算の責任との2つの責任があることがわかります。このような状態がSRP違反です。
SRP違反を起こすと、ある責任に対する変更が他の責任に影響し、予期せぬ不具合を引き起こす可能性があります。
今回は単純な例ですが、クラスの規模が大きくなり責任がさらに増えた場合ではより深刻な問題へと発展することも考えられます。特に永続的なものと頻繁に変更が行われるものを1クラスにまとめてしまうことは良くないです。
SRP準拠
上記の違反しているGlyphクラスをSRPに準拠した形に設計し直してみましょう。
もともとGlyphクラスは描画の責任と計算の責任の2つの責任を持っていました。
そこで、計算の責任を新しいMath Glyphというクラスに移譲しましょう。これにより描画に関してはGlyphクラス、計算に関してはMath Glyphと1つのクラスに1つの責任となります。
ペイントアプリは文字の描画責任を持ったGlyphクラスを利用し、フォントエディタは文字を編集するためMath Glyphを利用することとなります。
SRP違反の例外
クラスが持つ複数の責任が互いに悪影響を及ぼさないことが明らかな場合にはSRPに準拠しなくても良いことがあります。
責任ごとにクラスを分けることでクラスが多くなり冗長となってしまう場合もあるため、このような状況で悪影響がないのであればそれらの責任はまとめて1クラスにすることが自然です。
おわりに
オブジェクト指向でクラスなんかを作るときは、ちゃんと設計とかも気にしていきたいですね…