Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Application Design 勉強会 #3

Application Design 勉強会 #3

k-kohey

July 12, 2019
Tweet

More Decks by k-kohey

Other Decks in Programming

Transcript

  1. "QQMJDBUJPO%FTJHO ษڧձ

    ஜ೾େֶ ৘ใϝσΟΞ૑੒ֶྨ೥
    ઒ޱ ߤฏ
    1

    View Slide

  2. Ϧείϑͷஔ׵ݪଇʢ-41ʣ
    2

    View Slide

  3. Ϧείϑஔ׵ͷݪଇʢ-41ʣ
    「派⽣型はその基本型と置換可能でなければならない.」
    この原則に反すると,OCPにも反することとなりプログラムが脆くなる.
    - 関数fがある基本クラスAをその引数に取り
    - Aの派⽣クラスCを関数fに渡した際において異常を起こした…とする
    - この場合にクラスCはLSPに従わないという
    LSPはOCPを有効にする⼿段の1つであり
    あるモジュールに修正を施さずに拡張する⽅法として,基本型と派⽣型の置換性という形で表している
    3

    View Slide

  4. Ϧείϑஔ׵ͷݪଇͷྫ
    • 「派⽣型はその基本型と置換可能でなければならない.」
    • この原則に反すると,OCPにも反することとなりプログラムが脆くなる.
    4
    • UserやBookがEntityの代わりとして扱えないことに
    よって,LSP違反が起きている.
    • Entityがidentifierを持つことを担保すればこの問題
    は起きない
    • また,Entityの種類が増えると分岐が増えるので
    OCP違反をしている.
    • LSP違反は⾃然にOCP違反を引き起こす.

    View Slide

  5. Ϧείϑஔ׵ͷݪଇʢ-41ʣ
    • 「派⽣型はその基本型と置換可能でなければならない.」
    • この原則に反すると,OCPにも反することとなりプログラムが脆くなる.
    5
    • UserやBookがEntityの代わりとして扱えないことに
    よって,LSP違反が起きている.
    • Entityがidentifierを持つことを担保すればこの問題
    は起きない
    • また,Entityの種類が増えると分岐が増えるので
    OCP違反をしている.
    • LSP違反は⾃然にOCP違反を引き起こす.
    この例では,単なる継承によって解決する.
    継承によってLSPを満たせない場合はあるのか?

    View Slide

  6. ܧঝʹΑͬͯෳࡶԽ͞Εͨ-41ҧ൓ͷྫ
    • この⻑⽅形を表すRectangleViewに加えて正⽅形を表すSquareViewを追加する必要が出てきたケース.
    • 継承はIS-A(「である」)の関係であるといわれている.
    • 正⽅形は⻑⽅形であるのでSquareはRectanbleのサブクラスになりそうだ.
    6

    View Slide

  7. ܧঝʹΑͬͯෳࡶԽ͞Εͨ-41ҧ൓ͷྫ
    • 本来⼀辺を設定できれば良いが,継承によって不要なメソッドを受け継いでしまった.
    • したがって,下記のように両辺の⻑さが等しいことを担保した.
    • 結果,Squareの性質を担保することが出来た!
    7

    View Slide

  8. ܧঝʹΑͬͯෳࡶԽ͞Εͨ-41ҧ൓ͷྫ
    • 結果,Squareの性質を担保することが出来が……
    • クライアントによっては下記のコードのような間違いが起きる.
    8
    関数fにSquareViewを与えたときに,assertでエラーが発⽣する.
    SquareViewはIS-Aの関係を満たしており正⽅形本来の性質も満たしている.
    じゃあ,このコードには正当性があり,間違っているのはクライアント?

    View Slide

  9. ܧঝʹΑͬͯෳࡶԽ͞Εͨ-41ҧ൓ͷྫ
    • 結果,Squareの性質を担保することが出来が……
    • クライアントによっては下記のコードのような間違いが起きる.
    9
    関数fにSquareViewを与えたときに,assertでエラーが発⽣する.
    SquareViewはIS-Aの関係を満たしており正⽅形本来の性質も満たしている.
    じゃあ正当なのか?
    このコードが間違っているのだろうか?
    LSPに準拠するためにはIS-Aの関係では不⼗分.
    「振る舞い」の同等性も必要!
    誰もが合理的だと思う振る舞いをIS-Aに持たせる.

    View Slide

  10. ܖ໿ʹΑΔઃܭ
    • 合理的な仮定を明確にするテクニック.
    • あるメソッドについての事前条件と事後条件を決めておくことによって,そのメソッドを利⽤する⼈が
    必要としている振る舞いを知る事ができる.
    • 事前条件: そのメソッドを実⾏する前に成⽴していなければいけない条件
    • 事後条件: メソッドが終了したときに成⽴していなければならない条件
    • 基本クラスをインタフェースにした場合に,クライアントが理解しているのは基本クラスの事後条件と
    事前条件のみ
    • 派⽣クラスの事前条件は基本クラスに課せられている事前条件より強くしてはいけない.
    • 派⽣クラスの事後条件は基本クラスの事後条件より弱くしてはいけない.
    Square::setWidthはRectanbleより事後条件が弱い.よって設計契約に反する.
    -> 振る舞いの同等性が担保されていない
    10

    View Slide

  11. ܦݧଇʹґΔ͓खܰ-41ҧ൓νΣοΫ
    • Overrideによって関数の機能が劣化しているケース
    • 基本クラス以下のことしか出来ないのであれば置換は不可能.
    • 基本クラスでは投げない例外を派⽣クラスによって投げられているケース
    • 基本クラスの利⽤者がその例外を期待していないのでれば,置換不可能.
    • = 事前条件が強まってる??
    11

    View Slide

  12. ґଘੑٯసͷݪଇʢ%*1ʣ
    12

    View Slide

  13. ґଘੑٯసͷݪଇʢ%*1ʣ
    上位のモジュールは下位のモジュールに依存してはならない.
    どちらのモジュールも抽象に依存すべきである.
    抽象は実装の詳細に依存してはならない.実装の詳細が抽象に依存すべきである.
    • 悪しき⼿続き型プログラミングでは⽅針が実装に依存する
    • 抽象と実装の詳細を完全に切り分けることによって変更に強くなる
    • 再利⽤性も⾼まる
    13

    View Slide

  14. %*1ͷϞνϕʔγϣϯ
    • アプリケーションの⽅針といったビジネスモデルを含む上位モジュールが下位のモジュールに依存する
    と,下位のモジュールの変更が上位モジュールに影響する.
    • それは本来逆であるべき.⾃分たちが使いたいのは上位のモジュールであるはず.
    14
    ґଘੑͷٯస
    下位モジュールから上位モジュールへの

    View Slide

  15. %*1ʹΑͬͯӨڹ͕఻ൖ͠ʹ͍͘֊૚ߏ଄Λ࡞Δ
    • オブジェクト指向の⾔語では明確に定義付けられた階層を持つ
    • 上位のモジュールがインタフェースを持つことによって,下位のモジュールは上位のモジュールに依存
    する.
    • インタフェースによって詳細の実装を隠蔽されているため上位のモジュールは下位のモジュールに依存
    しない.
    15
    本書p165より転載
    本書p165より転載

    View Slide

  16. %*1ҧ൓ͷྫ
    16
    Button
    Lamp

    View Slide

  17. %*1ద߹ͷྫ
    17
    Button
    SwifthableServer
    Lamp

    View Slide

  18. %*1ద߹ͷྫ
    18
    Button
    SwifthableServer
    Lamp
    Buttonによって制御されるオブジェクトは全てButtonServerに準拠しなくてはいけない,というの
    は問題.Switchなどを操作することもある.
    ー> 命名を⼀般的にすることによって解決

    View Slide

  19. ந৅ʹґଘͤΑ
    • DIPは抽象に依存せよ,という経験則とも⾔える.
    • 具体的なクラスへのポインタやリファレンスを保持するような変数があってはならない
    • 具体的なクラスから派⽣するクラスがあってはならない
    • 基本クラスで実装されているメソッドを上書きするようなメソッドがあってはならない.
    19

    View Slide

  20. Πϯλϑʔε෼཭ͷݪଇʢ*41ʣ
    20

    View Slide

  21. ΠϯλϑΣʔε෼཭ͷݪଇ
    • 太ったクラスはそれを利⽤するクライアント同⼠で良くない問題を起こす.
    • 例えば,あるクライラントが依存先のクラスに変更を要求すると,別のクラスに変更の影響が伝搬する
    可能性がある(OCP違反)
    • クライアントごと(もしくはクライアントのグループ)に必要なメソッドを切り出したインタフェース
    を作成することによって,この問題は解決できる.
    • 結果,クライアントは⾃⾝が利⽤しないメソッドとの依存関係を切り捨てられる.
    21
    ΠϯλϑΣʔεͷ෼཭
    クライアントに⾃⾝が利⽤しないメソッドへの依存を強要してはならない

    View Slide

  22. ΠϯλϑΣʔε෼཭ͷྫ
    • これらの定義を⽤いて⻑時間ドアが空いているとロックされるTimedDoorを実装する.
    22

    View Slide

  23. ΠϯλϑΣʔε෼཭ͷྫ
    • よくある⼿法(らしい)
    • この⼿法ではTimerDoor⾃体がタイムアウトの通知を
    受けられる利点がある⼀⽅でDoorがTimerDoorに依存
    してしまう問題がある.
    • これはインタフェースを太らすインタフェースの汚染
    である.
    • また,この⼿法はLSPに違反する.
    23
    • これらの定義を⽤いて⻑時間ドアが空いているとロックされるTimedDoorを実装する.

    View Slide

  24. ΠϯλϑΣʔε෼཭ͷྫ
    • よくある⼿法(らしい)
    • この⼿法ではTimerDoor⾃体がタイムアウトの通知を
    受けられる利点がある⼀⽅でDoorがTimerDoorに依存
    してしまう問題がある.
    • これはインタフェースを太らすインタフェースの汚染
    である.
    • また,この⼿法はLSPに違反する.
    24
    • これらの定義を⽤いて⻑時間ドアが空いているとロックされるTimedDoorを実装する.
    インタフェースの分離=クライアントの分離
    DoorとTimeClientは異なるクライアントにインタフェースを
    提供する.ならばインタフェースを分離させるべき.

    View Slide

  25. ΠϯλϑΣʔε෼཭ͷྫ
    25
    Adapterパターンを⽤いた⽅法
    多重継承を⽤いた⽅法

    View Slide

  26. Ҿ༻
    • ロバート・C・マーチンほか.アジャイルソフトウェア開発の奥義 第
    2版 オブジェクト指向開発の神髄と匠の技. SBクリエイティブ, 2008
    26

    View Slide