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

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

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

qiita.com

この記事は「Hamee Advent Calendar 2021」9日目の記事です🙌

9日目

こみゃみゃちな〜〜〜〜〜〜〜〜〜!!!!
みんな〜〜〜〜〜!!!今日1日元気にしてた〜〜〜〜!?このブログ読んでる人が全員まとめて幸せになります様に〜〜〜!!!(完)〜〜〜!!!

私は今日こんな1日だったよ!

前回までのあらすじ

asumikan.hatenablog.com

※ 前回の記事を見ていない方はそちらから見ていただくと良いカモです❣️繋がるモンは繋がるとおもいます❣️円環の理〜

愛2日目!!!!!!愛も折り返し地点きましたね。よろしくお願いします。

前回は「流動的要素」と「Strategyパターン」についてつらつらと文章を書かせていただきました。アンチパターンにStrategyパターンを適用する際に「何やらSOLID原則っぽい動きをしているかもしれない・・・」と気付いたあすみちゃん。今日は「SOLID原則」が本の中で記述されている部分について言及し、その後「Decoratorパターン」の章を見ていこうと思います!🙌

あとめっちゃどうでもいいんですけどアイキャッチの「Calendar」の綴り間違えてたので修正しました。カレンダーって綴り間違わないで書くのめっちゃ難しくないですか?

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

デザインパターンと「SOLID原則」

そもそも「SOLID原則」とは?

それぞれの詳細な説明はしません!(せんのかい!)
その代わりに、とてもわかりやすく纏まっていて理解する上で大変参考になった記事を紹介させてください...!生まれてきてくれてありがとう...

qiita.com

note.com


あすみ的解釈

  • S ... 単一責任の原則
    • 1つのクラスは1つのことしかやらないようにしようね!
  • O ... 開放/閉鎖原則
    • 拡張する際はしやすく(開放・オープン)、変更する時は影響範囲が小さくなるように(閉鎖・クローズド)しようね!
  • L ... リスコフの置換原則
    • 「子」は親と似た様な形式のアウトプットを提供しようね!
  • I ... インターフェース分離の原則
    • 色んな意味を持った1つのインターフェースではなく、シンプルな複数のインターフェースにしてこうね!
  • D ... 依存性逆転の原則
    • 依存する方向は片方向にしようね!さらに、具体が抽象に依存する形にしようね!

デザインパターンと「SOLID原則」の関係

そもそもデザインパターンと言われるものは「SOLID原則」の概念に基づいてパターンが生み出されてるのかな?

「オブジェクト指向のこころ」から学ぶStrategyパターン - #あすみかんの上にあすみかん

▲ 昨日の自分の発言なのですが、
▼ 見事、第14章で回収されていました・・・!

この章では、以下のことを解説しています。

  • 多くのデザインパターンの根幹にある開放/閉鎖原則(open-closed principle)を解説しています。
  • Alexanderがパターンに求めた、コンテキストからの設計原則を考察しています。この過程で、デザインパターンの要とも言える、依存性の逆転原則(dependency inversion principle)とリスコフの置換原則(Liskov substitution principle)という2つの原則を解説しています。

(p.223 - 14.1 概要)

ウオ〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜🐟❗️ やっぱり、デザインパターンの根幹には「SOLID原則」あるョヮナ・・・!と噛み締めました。
この章で明示的に触れられているのは「O」と「L」「D」ですが、多分他のも関わってるんだろうなと思いました・・・!ので!ちょっと本に沿って昨日の「Strategyパターン」を「SOLID原則」で当てはめていく遊びをしてみたいと思います 🐈

「Strategyパターン」から「SOLID原則」を感じ取る

S ... 単一責任の原則
  • 「税計算」のみで責任を分離した部分
O ... 開放/閉鎖原則

開放/閉鎖原則の本質的な意味合いは、新たな機能を個別に、すなわちモジュール化された形で追加していける様にすること(後略)
(p.224 - 14.2 開放/閉鎖原則)

  • 各々をオブジェクトとしてまとめていること
L ... リスコフの置換原則

基底クラス(すなわちインターフェース)への参照を用いることで、それを使っているオブジェクトから派生クラス(すなわち実装)の存在を隠す様にするのです。
(p.226 - 14.3 コンテキストからの設計原則)

  • Configurationからもらったオブジェクトが何であるかは気にせずに「税計算」を呼び出している部分
  • CanTax・USTaxの「税計算」の返り値の型は同じである部分
I ... インターフェース分離の原則
  • 「税計算」のみでインターフェース(Abstractクラス)を作っている部分
D ... 依存性逆転の原則

目の前にある特殊な状況でなく、抽象的側面を具体化したものの中で表現される概念のニーズを考えるのです。
(p.224 - 14.3 コンテキストからの設計原則)

  • 呼び出し側(SalesOrder)が、呼び出される側(CanTax / UXTax)のことを意識していない部分
  • 親クラス(CalcTax)が子クラス(CanTax / USTax)を意識していない部分
どうじゃろか!?

・・・探してみるとやっぱSOLID原則使われてるな・・・根源なんだなという思いが深まりました。もしかしたら、デザインパターンによって、SOLID原則のどこが色濃く出ているかは変わってくるのかもな?と思いました。この後で出てくるDecoratorパターンでも適用させてみます 🧩 ✨

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

前提

  • 前回と同様、国際e-コマース企業が使う受注処理システムのお話
  • 今回は「伝票」部分に着目する
  • システムの登場人物
    • TaskControllerくん
      • 発生した注文に「アレしてきて」「コレしてきて」と制御をする責任をもつ。
    • SalesOrderくん
      • 「伝票作成の結果をもらう」責任を負う
      • 共通の「Header」「Footer」を1つずつくっつける
    • SalesTicketくん
      • 「伝票を作成する」責任を持つ
シーケンス図っぽいもの
課題・膨らむ要求
  • Header・Footer別の種類のもの作って欲しいんだけど!
  • HeaderとFooter、各々複数個付けられるようにできない?
伝票のイメージ

SalesTicketくんは「伝票を作成する責任を持つ」オブジェクトとして分離されていたので「税計算」の時よりは優秀なオブジェクトでした。そのため、上記図の「種類がふえる」までは「Strategyパターン」が適用しやすい状況にあります。
ただし、今回はそれの先があり、「各々複数個つけられるようにしたい」「ヘッダー内の要素の順番は任意にできない?」などの要求が生まれてくる事態となりました。

このような状況の際に、Decoratorパターンが活きてきます✨

解決方法・Decoratorパターン

Decoratorパターンは、付加する機能に対して責任を持つDecoratorというオブジェクトから始まり、元々からある機能を表すオブジェクトで終了する、一連のオブジェクト連鎖を生成することによって機能します。
(p.261 - 17.3 Decoratorパターン)

つまり、「種類が増え」「使える数が増えた」ヘッダー・フッターの実装は下記の様に呼び出すことによって解決します。
(この「連鎖」を実装するために少し技の効いた実装が必要なのですが、今日触れたい本質ではないので割愛します。)

<?php
new Header1(new Header2(new Footer1(new SalesTicket())));
デコられていくサマ

Header1や、Header2、Footer1、などを「連鎖できるパーツ」として定義し、呼び出し側で好きに組み合わせる = デコるようにしてるのがミソですね🙌
「連鎖順」の管理は、Strategyパターンと同じ様にConfigurationあたりが担うのかな〜と思いました💡

シーケンス図っぽいのを書いてみた

先ほどの連鎖部分は以下の様に分解できます。

<?php
$component = new SalesTicket();
$component = new Footer1($component);
$component = new Header2($component);
$component = new Header1($component);

本の中では「Factory」としている部分を「Strategyパターン」と同様、「Configuration」という概念を適用してみました。
「Configuration」からは、適用するデコクラスの文字列が配列かなんかで渡されるイメージ

Decoratorパターンを適用したシーケンス図っぽいやつ

これを書くことで若干複雑っぽく見えちゃってる気もするので、、ちょっとこれはクラス図の方がもしかしたらわかり良いかもしれません💧

偉大なる先輩に手伝っていただいて🙇‍♀️🙇‍♀️🙇‍♀️、本物のシーケンス図も書いてみました。
こっちの方が、連鎖感の部分は納得できるかも?

ちゃんとしてるシーケンス図

あすみめも!

Decoratorパターンとは

  • 以下の雰囲気の時は「Decoratorパターン」の適用どころかも!
    • 大元の何かに付随させるパーツがある
    • パーツの数や組み合わせを自由に組みたい
    • よりシンプルなものはもしかしたら「Strategyパターン」なのかも?
「Decoratorパターン」から「SOLID原則」を感じ取る
S ... 単一責任の原則
  • 「デコパーツ」をそれぞれ分離している部分
  • 「SalesOrder」は「SalesTicket」ならびにデコパーツのことは全く知らない部分
O ... 開放/閉鎖原則
  • 「デコパーツ」をそれぞれ定義している部分
  • 「大元のSalesTicket」と「デコパーツ」を並列概念として扱っている(継承させていない)部分
L ... リスコフの置換原則
  • 「デコパーツA」と「デコパーツB」は交換可能である部分
I ... インターフェース分離の原則
  • 「Component(大親)」と「Decorator(親)」でインターフェース(抽象クラス)を分けている部分
D ... 依存性逆転の原則
  • 「Decorator(親)」は「デコパーツ(子)」の実装を知らないという部分
どうじゃろか!?

なんか思ったよりもうまく書けなかったな、、!気づいてない部分とかもありそう😢!ただ、「書くまでもなくこれは『そう』でしょ(Strategyパターンの時もそうだったしな)」みたいな感情がありつつ書いたので、本当に「SOLID原則」はデザインパターン に溶け込んでるな〜とより実感しました!

次回予告

てなわけで明日もう最終日か・・・!ここまでデザインパターンを雑に2つ紹介してきました。

「振る舞いに関するStrategyパターン」・「構造に関するDecoratorパターン」だったのですが・・・あれ?そういえばそれぞれ3区分の説明してないな?👼
と思ったところで、そこの説明をしている部分がこの後の章に出てきたので

  • 「振る舞い」「構造」「生成」ってなんなのょさ〜〜〜!
  • 最後は「生成」!Singletonパターンについて話すゎよ〜〜〜〜!

明日はコチラのラインヌャップでいきたいと思います!!!じゃ〜〜〜〜また明日な。ブュッ。