オブジェクト指向設計の原則

JavaプログラマのためのUML」から,簡単なまとめ(メモ)。

設計品質

設計の臭い
  • 硬直性:変更しにくいシステム。変更の影響範囲が広い
  • 脆弱性:一部を変更するとあちこちに綻び(エラー)が生じるシステム
  • 低移植性:分割できない複雑なシステム
  • 粘着性:?
  • 不要な複雑さ:今必要でない将来のための汎用性による複雑さ。YAGNIの原則違反
  • 不要な繰り返し:コピペによる重複したコード
  • 不透明さ:分かり難さ,設計意図が見えない
依存関係の管理

複雑に絡み合ったコードにならないように依存関係を管理する。

クラス設計の原則

クラス,モジュール設計における原則。クラス分割,依存関係の指針。

  • 単一責務の原則(SPR: Single Responsibility Principle)
    • クラスを変更する理由がただ一つになるように,責務を一つにする
      • 自分の持つ属性に責任を持つなら,外部の環境に依存してはならない(entity)
  • 開放/閉鎖の原則(OCP: Open-Closed Principle)
    • 変更せずに簡単に拡張できるようにする
      • インタフェースと実現クラスに分割して拡張できる構造にする
  • リスコフ置換の原則(LSP: Liskov Substitution Principle)
    • 利用者が派生クラスを基本クラスとして利用できようにする
      • 利用者に派生クラスの型を気にさせてはならない
      • ダウンキャスト,instanceofの利用は硬直性,脆弱性,低移植性の臭い
  • 依存関係の逆転の原則(DIP: Dependency Inversion Principle)
    • インタフェースや抽象クラスに依存するようにする
      • 高レベルが低レベルに依存してはならない
      • 抽象が詳細に依存してはならない。詳細が抽象に依存する
  • インタフェース分離の原則(ISP: Interface Segregation Principle)
    • 利用者が使うだけのメソッドのインタフェースを提供する
      • 利用者に不必要なメソッドを提供しないインタフェースにする
      • インタフェースも単一責務の原則(SPR)に従う
原則はいつ適用すべきか
  • 苦痛を感じた時にはじめて原則を適用すべし
    • 最初から全ての原則に適合させようとしてはだめ。必要以上に検討することが増えてしまう
  • 何か問題が起こった時に受動的に適用する
    • ただし,問題の発見は能動的に行うこと

パッケージ設計の原則

パッケージ,コンポーネント設計における原則。クラスのグルーピング(パッケージ化),パッケージ間の関係に関する指針。

  • 公開/再利用等価の原則(REP: Release/Reuse Equivalency Principle)
    • 再利用しやすい単位にパッケージを作成する
      • 再利用が可能なら公開も可能
  • 共通閉鎖の原則(CCP: Common Closure Principle)
    • 変更が局所化されるようにパッケージにまとめる(SPRの適用)
  • 共通再利用の原則(CRP: Common Reuse Principle)
    • (ISPの適用)
  • 非循環依存関係の原則(ADP: Acyclic Dependencies Principle)
    • 独立して作業できるように,依存関係を循環させない
  • 安定した依存関係の原則(SDP: Stable Dependencies Peinciple)
    • 安定した(変更されにくい)パッケージに依存する
      • 変更されやすいパッケージに依存してはならない
  • 安定した抽象化の原則(SAP: Stable Abstructions Principle)
    • 変更せずに簡単に拡張できるようにする(OCPの適用)

まとめ

設計の原則

オブジェクト指向設計の原則は,高凝集度,低結合度により,再利用性,拡張性を満たすための設計指針。
でも,最初からすべての原則に適合するように設計する必要はない。必要になったときに原則に立ち返ればよい。
気づいた時に変更しやすいように,まずはシンプルに設計することが重要。

シンプルな設計

複雑なモジュール,モジュール間の複雑な関係はシステムを硬直化させる。依存関係の管理は,「肝となる関係」と,実行環境やその他の要求に影響される「肝でない関係」を明確にすることが重要だと思う。
クラスはシンプルにして,クラス間の関係は「肝となる関係」を残し,外部環境や仕様変更の対象になり得る「肝でない関係」を分離したい。パッケージは再利用しやすく凝集度の高い単位に分割し,パッケージ間の依存関係を切り離したい。

DI(Dependency Injection)

「依存性の注入」と訳される。
シンプルな設計で分離した部分をDIによって繋ぎ合わせることにより,シンプルで本質的な構造のパッケージになり,再利用性,拡張性も持たせられるはず。
また,分析段階での理解のためのモデルを,今以上に設計にスムーズに繋がるはず。