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

Application Design 勉強会 23-25章

0e742980c48d689f31700b208f22fd5a?s=47 k-kohey
September 12, 2019

Application Design 勉強会 23-25章

0e742980c48d689f31700b208f22fd5a?s=128

k-kohey

September 12, 2019
Tweet

More Decks by k-kohey

Other Decks in Technology

Transcript

  1. "QQMJDBUJPO%FTJHO ษڧձ ষ ஜ೾େֶ ৘ใϝσΟΞ૑੒ֶྨ೥ ઒ޱ ߤฏ 1

  2. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 2
  3. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 3
  4. ষ $PNQPTJUFύλʔϯ • オブジェクトを管理するクラスが 管理対象のオブジェクトの集合体としてふるまうパターン • 実際は1:nの関係にあるものを1:1の関係であるように⾒せられる • 理解が簡単 •

    コーディングが楽 • 保守が楽 4
  5. $PNQPTJUFύλʔϯͷྫ 5 protocol Shape { func draw() } struct CompositeShape:

    Shape { let shapes: [Shape] func draw() { shapes.forEach { $0.draw() } } } Composite⾃体がShapeに準拠 CompositeはShapeを保持 Shapeと同じインタフェースを使って 複数のShapeをDraw
  6. ·ͱΊ • Compositeパターンはほとんどコードに変更を与えずに導⼊できる • 1:nの関係を1:1の関係のように⾒せかけることによって,コードを簡単に出来る • 管理対称のオブジェクトを同⼀と⾒なせない場合にこのパターンは⽤いるべき ではない • 例)従業員のリストから今⽇が給料⽇の従業員を取り出す

    6
  7. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 7
  8. ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • リファクタリングの過程によってデザインパターンに回帰する • デザインパターンは天下り的に与えられない • 下記のコードがリファクタリングの結果,Observerパターンに回帰します. 8

    OSから与えられる時間情報clockを使って アプリケーション上に時間を表⽰するコード
  9. ষ αϯϓϧίʔυͷ໰୊఺ • Whileによって無駄なループが発⽣している • CPUを必要以上に専有してしまっている • 時間を取得するのはClockが保持する時間が更新されたタイミングのみでいいはず 9 OSから与えられる時間情報clockを使って

    アプリケーション上に時間を表⽰するコード
  10. ষ αϯϓϧίʔυͷվળᶃ • TimeSource(Clockの抽象型)の変更を TimeSinkクラスに通知する. • 2者間の通知には,ClockDriverを介して⾏う • 時間が変更したときのみ,TimeSinkに時間が流れる 10

  11. ষ αϯϓϧίʔυͷվળᶃ • TimeSource(Clockの抽象型)の変更を TimeSinkクラスに通知する. • 2者間の通知には,ClockDriverを介して⾏う • 時間が変更したときのみ,TimeSinkに時間が流れる 11

    問題点 TimeSourceがClockDriverに依存 誰でもTimeSourceを使えるようにしたい
  12. ষ αϯϓϧίʔυͷվળᶄ • ClockObserverを作成 • ClockDriverはClockObserverに準拠 • TimeObserverはClockObserverに依存するように 変更 12

  13. ষ αϯϓϧίʔυͷվળᶄ • ClockObserverを作成 • ClockDriverはClockObserverに準拠 • TimeObserverはClockObserverに依存するように 変更 13

    問題点 複数の時計を表⽰するような場合 複数のsinkを許容する必要がある 問題点 update(:Time)とsetTime(:Time) は同じ事をしている ClockDriverは必要無い
  14. ষ αϯϓϧίʔυͷվળᶅ • Driverを消去 • TimeSourceが複数のObserverを管理する ように変更 14

  15. ষ αϯϓϧίʔυͷվળᶅ • Driverを消去 • TimeSourceが複数のObserverを管理する ように変更 15 問題点 TimeSourceに準拠するクラス全てが

    このメソッドを実装しなくてはいけない
  16. ষ αϯϓϧίʔυͷվળᶅ • Baseクラスを作り, Observerに関する処理は 親クラスに詰め込んだ 16

  17. ষ αϯϓϧίʔυͷվળᶅ • Baseクラスを作り, Observerに関する処理は 親クラスに詰め込んだ 17 問題点 名前からObserverを管理することを 察せられない

  18. ষ αϯϓϧίʔυͷվળᶆ • Subjectという名前を使⽤ • Subjectの名前に合うように 値の取得⽅向を逆転させた 18

  19. ষ αϯϓϧίʔυͷվળᶆ • Subjectという名前を使⽤ • Subjectの名前に合うように 値の取得⽅向を逆転させた 19 Observerパターンに なりました

  20. 0CTFSWFSύλʔϯɼԿ͕خ͍͠ͷ͔ • OCPに準拠する • 監視対象のオブジェクトを⼀切修正せずに,Observerのオブジェクトを追加できる • LSPに準拠する • 例)ClockはSubjectと置換可能 •

    DIPに準拠する • 今回の例ではSubjectが具体型であったが, Subjectが単体でインスタンス化することはないので論理的には抽象型 20
  21. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 21
  22. ষ "CTUSBDU4FSWFSύλʔϯͷྫ • 下記のような設計について考える • Swtichが物理的なスイッチ状態をポーリング • SwitchがLightに依存しており,状態をLightに伝える 22 Switch

    Light + turnOn + turnOff
  23. ষ "CTUSBDU4FSWFSύλʔϯͷྫ • 下記のような設計について考える • Swtichが物理的なスイッチ状態をポーリング • SwitchがLightに依存しており,状態をLightに伝える 23 Switch

    Light + turnOn + turnOff DIP違反 具体的な型に依存している OCP違反 Switchが必要な場合にはLightも連れていかないと ダメ
  24. ষ "CTUSBDU4FSWFSύλʔϯͷద༻ • SwitchはSwitchによって制御可能なSwitchableに依存 • SwitchableはインタフェースなのでDIPに準拠 • 同時にOCPにも準拠 24 Switch

    <interface> Switchable + turnOn + turnOff Light + turnOn + turnOff
  25. ষ "CTUSBDU4FSWFSύλʔϯͷద༻ • SwitchはSwitchによって制御可能なSwitchableに依存 • SwitchableはインタフェースなのでDIPに準拠 • 同時にOCPにも準拠 25 Switch

    <interface> Switchable + turnOn + turnOff Light + turnOn + turnOff インタフェースはクライアントに属する Lightが継承しているからといってLightInterfaceと いった名前にしない. Switch(クライアント)が使うのでSwitchable.
  26. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 26
  27. ষ "EBQUFSύλʔϯͷྫ • 下記のような設計について考える • Swtichが物理的なスイッチ状態をポーリング • SwitchがLightに依存しており,状態をLightに伝える 27 Switch

    Light + turnOn + turnOff もしLightがサードパーティが作ったもので Switchableに準拠させられない場合は....?
  28. ষ "EBQUFSύλʔϯͷదԠ • 間に⼀枚挟んで,Interfaceの変換のような事を⾏う • このように,Adapter⾃⾝がAdapte対称を継承することをクラス形式のAdapterパターンという 28 Switch <interface> Switchable

    + turnOn + turnOff LightAdapter + turnOn + turnOff Light + turnOn + turnOff
  29. ষ "EBQUFSύλʔϯͷదԠ • 間に⼀枚挟んで,Interfaceの変換のような事を⾏う • このように,Adapter⾃⾝がAdapte対称を継承することをクラス形式のAdapterパターンという 29 Switch <interface> Switchable

    + turnOn + turnOff LightAdapter + turnOn + turnOff Light + hogehoge + fugafuga ここは何でも良い
  30. ໨࣍ • ষ $PNQPTJUFύλʔϯ • ষ 0CTFSWFSύλʔϯ σβΠϯύλʔϯ΁ͷճؼ • ষ

    • "CTUSBDU4FSWFSύλʔϯ • "EBQUFSύλʔϯ • #SJEHFύλʔϯ 30
  31. ষ #SJEHFύλʔϯͷྫ • 下記のようなモデムを表現した実装がある • このモデルにdialとhangupが必要ないDelicated Modemが追加されることとなった • すでにこのシステムは多くの顧客に使われており,インタフェースを分離できない 31

  32. ষ #SJEHFύλʔϯͷྫ • 問題の根底が下記のような依存関係になった,と捉えると Bridgeパターンが適応出来る 32

  33. ষ #SJEHFύλʔϯͷదԠ • 各もモデムの振る舞いは ModelImlpletetionに譲渡 • ストラテジーパターン? • Delicated Modemの場合は

    dialとhangupだけを実装 33
  34. ষ ·ͱΊ • 仕様変更の要求は必ず起こる上に時間は有限 • ⼗分な分析は常に出来ないので,コストと利益とのバランスが取れるように設計していく 必要がある • Adapterパターンを使った⽅法 •

    実装がシンプル • 全ての依存関係が正しい⽅向に向くようになっている • Bridhgeパターン • 構造を完璧に分離する必要がある • 拡張性は⾼い 34
  35. Ҿ༻ • ロバート・C・マーチンほか.アジャイルソフトウェア開発の奥義 第 2版 オブジェクト指向開発の神髄と匠の技. SBクリエイティブ, 2008 35