#あすみかんの上にあすみかん

#たのしいことしかかかないことをここに決意します

「オブジェクト指向のこころ」から学ぶStrategyパターン

qiita.com
この記事は「Hamee Advent Calendar 2021」8日目の記事です🙌

8日目

こにゃにゃちわ〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜!!!!!!!!!!!!!!!
みなさま1年間元気してましたでしょうか?
私は元気でした!よかったね!!!(完)!!!!!

この3日間、俺とお前が作る愛の物語の行方

現在Hamee開発部は3部体制になっており、各部10名ずついるのですが!私の所属している「開発3部」では、最近、「オブジェクト指向のこころ」を輪読しています💡

https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E3%81%93%E3%81%93%E3%82%8D-SOFTWARE-PATTERNS-%E3%82%A2%E3%83%A9%E3%83%B3%E3%83%BB%E3%82%B7%E3%83%A3%E3%83%AD%E3%82%A6%E3%82%A7%E3%82%A4/dp/4621066048www.amazon.co.jp

変化する要求に対してソフトウェアはどの様に設計していこうかね?
with design pattern ....(← 流暢な感じで...)

みたいな本です!(どんな本だ)
難しくて読むのが難しい*1ところもちょいちょいあるのですが、「こういうマインドで設計してこな!」の部分は納得感ハンパないので面白いな〜と思って読んでます🙌

なので!!今年は!!「オブジェクト指向のこころ」から、「あすみなりの解釈・要約をしつつ」「自分が勉強会を担当した部分の」「デザインパターンを紹介」していきます!😚
Advent Calendar2021...欲張って3日連続で書くことにしたので、デザインパターンは「振る舞い」「構造」「生成」という3分類を軸にしつつわちゃわちゃ記事を書いていくヮョッ!!気合入れっぞ!!オラ!!俺と!!3日間の「「「愛」」」育んでこな。


ブログ内でおもに触れている章!

「流動的要素」を見極める

「なぜ」存在するかを考えよう

「オブジェクトとは操作(メソッド)を伴ったデータである」...(略)...これらはあまりにも単純で安直なものの考え方と言えるでしょう。
(p.104 - 8.2 オブジェクト:従来からの考え方と新たな考え方)

カプセル化とは『データ隠蔽』である」...カプセル化とデータ隠蔽も同じものではありません。(略)...データ隠蔽は、カプセル化の限られた一面でしかないのです。
(p.106 - 8.3 カプセル化:従来からの考え方と新たな考え方)


「オブジェクト」や「カプセル化」を間違った解釈で生きていってしまってた時期って・・・ありますよね😨。確かにオブジェクトは「操作をまとめたもの」だし、カプセル化は「(データ)隠蔽」ではああります。でもこの説明は「HOW」でしかないからよくない説明方法なのかな、と思いました。概念の説明は「WHY(なぜそのようにする?)」の軸で話す方がより適していそうです。

あすみ的解釈

  • 責任を1つにまとめるために「オブジェクト」という概念が生まれ、「操作をまとめる」実装が為される
  • 流動的要素を適切に分離するために「カプセル化」という概念が生まれ、「データを隠蔽する」実装が為される

「第Ⅰ部 第1章 オブジェクト指向パラダイム」の「概念・仕様・実装」あたりの定義を以って説明してみました。
仕様にあたる部分に関しては上記の解釈では入れなかったのですが、流れを一気通貫でまとめると、「オブジェクト」「カプセル化」という概念がまず存在する。「実装したい条件・状況」が仕様となる。それを実装に落とし込む( = デザインパターンの適用)、みたいな感じなのかなあ。
・・・詳しい解釈は本を読んでくれ!!と投げ出してしまうのですが、確かにこの説明をパッとして理解してもらえることが少ないから、「HOW」によった説明が蔓延るのかなーと思いました。
(確かに、大学で習った時はガチで意味わからなかった。な〜〜にがチャーハンの作り方じゃコラ???と思いながら聞いてた)

流動的要素のカプセル化、そしてデザインパターンへ...

さて、上で重要な概念である「流動的要素」の言葉をサラっと出しました。
この概念はこの後も大事になってくるのでちょっとだけまとめます🍂

流動的要素とは

  • 流動的要素は「成長していくロジック部分」
    • 具体的な例の1つとして「顧客からの要求により変わっていく部分」
    • とりわけ、ドメインロジック的な部分が該当することが多いのかな

で、なぜこの流動的要素をカプセル化するか?というと、マジで平たく言うと「良い感じのコード*2書いていきたいよね!!」だと思ってます。

本の中で、「顧客の新たな要求(しかも突然だったりする)から、場当たり的なコードを生成してしまうことがある」という文脈があった上で以下の記述があります。

変更内容を正確に予測しようとしているわけではない...(略)...変更は将来必ず起こるものであるという前提に立ち、どこに変更が発生するのかを予測しようとしているのです。
(p.125 - 9.2 新たな要求を取り扱うための方法)

あすみ的解釈

  • 「どこに変更が発生するか?どこが膨らんでいきそうか?」=「どこが流動的要素か?」を見極める
  • その箇所を「カプセル化(等)」することによって「良い感じのコード」が書ける
  • これがいわゆる「デザインパターン」になっていった💭(先人の知恵的な感じだ)

「変更内容を正確に予測しなければならない」という脅迫概念が自分の中に存在していたので、この文章にはすごく救われました。無理なもんは無理だけど、どこが膨らみそうかは嗅いどいてな?スタイルめっちゃ良いな・・・!と・・・!˚✧₊⁎❝᷀ົཽ≀ˍ̮ ❝᷀ົཽ⁎⁺˳✧༚
(次に迫りくる問題として、「どこが流動的要素か?」を見極めるのが大変なのですが)

オブジェクト指向のこころ」から学ぶStrategyパターン

さて、タイトルにもある「Strategyパターン」の内容に入っていこうではありませんか・・・実際のデザインパターンを適用するサマをみていきましょう・・・!

前提

  • アメリカにある国際e-コマース企業が使う受注処理システムのお話
  • システムの登場人物
    • TaskControllerくん
      • 発生した注文に「アレしてきて」「コレしてきて」と制御をする責任をもつ。
      • 実際の「アレ」や「コレ」の中で何しているかは関心外
      • 「全体の流れ」と「アレ・コレ」の結果(決まったフォーマット)のみに興味がある
    • SalesOrderくん
      • 注文に関する責任をもつ。
      • 指定された「アレ」や「コレ」に関して、実際の処理をしていたり、実際の処理ができるオブジェクトを知っていたりする
      • 現状だと「税計算」は自前でもっており、「売上伝票印刷」はSalesTicketにお任せしている
シーケンス図だとこんな感じ

課題・膨らむ要求

  • カナダからの注文も受けて欲しいな!
    • 税計算がカナダのものを適用すること
    • 伝票は英語で記述すること(そのまま)
  • ドイツからの注文も受けて欲しいんだけど!
    • 税計算がドイツのものを適用すること
    • 伝票はドイツ語で記述すること
  • カナダのケベック州の注文にも対応して欲しいな!
    • 税計算はカナダのものを適用すること
    • 伝票はフランス語で記述すること
膨らむ要求!

この例の流動的要素が「国」であり、サービスの成長に伴い対応国がどんどん増えていきます(この膨らみ方・・・絶対みんな体験してるヮョナ・・・🌰 ✨)
「カナダからの注文も受けて欲しいな!」あたりまでは、伝票は英語だし、税計算の部分だけ分岐生やしちゃえ・・・と単純に「if文ブロックを生やす」で対応してしまいがちな人生です。この「場面対応」をしたことによって「ドイツからの注文も受けて欲しいんだけど!」「カナダのケベック州の注文にも対応して欲しいな!(どうやら伝票をフランス語で書かなければいけない)」とかのパンチも飛んできて「アッ!!!!・・・・・死・・・👼」となってしまうわけです・・・なんか、なんだろう、なんだこの懐かしい気持ちは!?俺たちはどこかでこんな経験をしているのですね。わっはっは

課題とその解決方法・Strategyパターン

Strategyパターンは以下の事実に基づいたものです。

  • オブジェクトには責務が存在する。
  • こういった責務を具体化したさまざまな実装を、ポリモーフィズムによって使い分けることができる。
  • 概念的に同じアルゴリズムに対する、さまざまな具体的実装を管理したいというニーズがある。

(p.136 - 9.5 Strategyパターン)

Strategyパターンを採用することによって、これらの規則を単一の抽象クラス内にカプセル化し、具体的な派生クラスのファミリを作り出すことができるのです。...(中略)...アルゴリズムのさまざまな実行方法を、抽象クラスから派生させて定義することにより、メインモジュールは実際にどういったアルゴリズムが使われているのかを気にしなくてもよいようになるのです。これにより、新たな流動的要素を追加できるようになります(後略)
(p.140 - 9.7 サマリ)

クラス図は本にある(し、調べたらたくさん出てくる)ので割愛して、今回のケースでStrategyパターンを適用したシーケンス図を書いてみます🙌
スコープを「税計算部分」のみに絞って記述します。(伝票のあたりの動きは省略)

Strategyパターンを適用したシーケンス図っぽいやつ
  • SalesOrderくん
    • 「税計算の結果をもらう」責任を負う
    • 元々は「国を判断し、税計算をして結果をかえす」というクソ重責任を担っていたが、各所適切な場所に聞き回る窓口的な存在になった
  • Configurationくん
    • 「指定された国から適切なクラスを渡す」責任を負う
    • 若干本質部分とはズレているのだが、「責任の分離」をしたというのが重要ポイント
  • CalcTaxくん
    • 「責任」を共通化している
      • 今回はextendsさせることで共通化させる
      • PHPなのであれば、これはabstract classで実装するのが良さそう
  • CanTax / USTaxくん
    • 「CalcTax」を継承している
    • 「具体的な国の税計算をする」責任を負う
      • これで、「日本」が増えても対応できる

あすみめも!

Strategyパターンとは

  • 以下の雰囲気の時は「Strategyパターン」の適用どころかも!
    • if文やswitch文でビャーーと伸びていってる
    • ロジックがそれぞれゴリゴリに書かれている
    • それぞれのロジックは並行概念だが、交わり合わない
  • 「Strategyパターン」の適用方法
    • 分岐部分でやっているそれぞれの「責任」を「オブジェクト」にする
    • 「具体的なオブジェクト」を特定して、ポリモーフィズム的に呼び出す流れをつくる

アンチパターンっぽいコードにStrategyパターンを適用させていく中で「責任を分散する」部分は「単一責任原則」(SOLIDのS)の動きが色濃く出てて、「各々をオブジェクトとしてまとめる」部分は「オープン・クローズドの原則」(SOLIDのO)の動きが色濃く出ているな〜〜とぼんやり思いました。(そもそもデザインパターンと言われるものは「SOLID」の概念に基づいてパターンが生み出されてるのかな?)

そんでもって、自分の中でもSOLIDについてフヤフヤなところあるな〜と思いました。たので、明日は「SOLID原則」について考えてもみようかと思います!具体的なデザインパターンと絡めて。
本日はこんなもんで失礼しますヮヨ〜〜〜〜〜また明日な!チュッ。

次回予告

  • SOLID原則まわりについて触れるゎよ〜〜〜
  • 上と絡めながら!Decoratorパターンについて触れるゎよ〜〜〜

*1:何も考えず手癖で書いた文章が小泉構文すぎたのでそのまま残しておくね?

*2:変更容易性 / 可読性 / 凝集度が高い / 結合度が低い / etc...