Single Responsibility Principle:単一責任原則

はい( todo か?)

Open Closed Principle

  • (拡張に) Open かつ (変更に) Close であれ(拡張はしやすく、変更はしづらくあるべき?)
  • Wikipediaより)メイヤーは1988年に著書「Object Oriented Software Construction」で以下のように語っている:
    • 拡張できるモジュールは開放されている == データ構造にフィールドを追加できる・関数を追加できる
    • 外部から使用できるモジュールは閉鎖されている == (外から見た?) 仕様が安定していて、実装が隠蔽されている
  • 「楽譜」クラスは「音符の種類」を自由に追加できるようにすべき(参考)だし、「楽譜」クラスが「音符の種類」に依存した構造をすべきではない
    • if note.kind == NoteKind::Quarter { Play(400) } else if note.kind == NoteKind::Half { Play(200) } ... とは書かず、 note.play() と書けるようにしたほうが良い)

Liscov Substitution Principle:リスコフの置換原則

  • 子クラスは「親クラスに期待される振る舞い」をしなければならず、そのために以下を守らなければいけない:
    1. 事前条件 (preconditions) は同じか弱くなければならない
    2. 事後条件 (postconditions) は同じか強くなければならない
      1. 戻り値が親クラスのそれと同じか、サブタイプでなければならない?
    3. 不変条件 (invaritants) は同じでなければならない
    4. 親クラスの例外から派生した例外ではない独自の例外を投げてはいけない
  • 親クラスにはどんな整数でも投げて良いのに、子クラスは除算があるから0を入れたら駄目、という仕様はこれに反している

Interface Separation Principle:インターフェース分離の原則

  • インターフェースが担う責任も単一でなければならない
  • Wikipedia いわく “no code should be forced to depend on methods it does not use” とのことらしい
  • ガラケーとスマホのために Phone インターフェースを作り、 そのインターフェースのために Call() と LaunchApp() を実装するのは、ガラケーはアプリを実行できない※のにインターフェースとしてそのメソッドを持つことになるという点で、よくない
    • ※後発のガラケーは普通に実行できるが?(今回は例なので……)
  • Callable および AppExecutable という2つのインターフェースに分けるべきということ?

Dependency Inversion Principle:依存関係逆転の原則

うわでた 抽象が詳細に依存するのではなく、詳細が抽象に依存せよ

データの編集が出来る Editor と、それを保存しておく Database が存在するとき、 Editor はデータを保存する先である Database に依存しそうだが、これらはどちらも詳細でよくない 

classDiagram
  Database <-- Editor
  class Editor {
    -string data
    -update_data(string)
    +commit()
  }
  class Database {
    -Vec<string> data
    +save(string)
  }
  

存先を示す Repository インターフェースを作り、Editor をそれに依存させることによって、Databaseじゃなくて File にしてくださいといった要求にも対応できる

classDiagram
  IRepository <--  Editor
  IRepository <|-- Database
  IRepository <|-- File
  class Editor {
    -string data
    -update_data(string)
    +commit()
  }
  class IRepository {
    <<interface>>
    +save(string)
  }
  class Database {
    -Map~string, string~ data
    +save(string)
  }
  class File {
    -string path
    -File file_handler
    +save(string)
  }