×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
<?php
/*
DIってなんだろう?
「依存性の注入」だそうで。
ソースコードの保全性向上とか、メンテナンスやらテストが綺麗にできるようになる
という事は聞いている。
単純な計算プログラムでも作って実感してみよう!
まずは、レガシーな書き方をしてみる。
Calcっていうクラスがあって、その中に各計算用のメソッドを用意して、
制御側でメソッドを呼び分けるという愚直なスタイル。
*/
// 計算するクラスだよ
class Calc
{
// 足し算するとき呼んでね
public function execAdd($left, $right)
{
return $left + $right;
}
// 引き算するとき呼んでね
public function execDiv($left, $right)
{
return $left / $right;
}
}
// では早速使ってみよう。「Add」か「Div」という文字を渡すと計算してくれるなかなかのやつ
$method = 'Add'; // 足し算をしよう
$left = 10; // 左辺は10
$right = 5; // 右辺は5としよう
// 計算機のお出ましだ
$calc = new Calc;
// 場合によって呼ぶメソッドを変えよう
if ($method === 'Add') {
$answer = $calc->execAdd($left, $right);
} elseif ($method == 'Div') {
$answer = $calc->execDiv($left, $right);
}
// とりあえず、$answerは15だった!
/*
まあ、こういう書き方は昔からありがちである。
なるほど、当然これだと処理が「Calcクラスの実装ありき」になってるので
Calcクラスのメソッド名とかが変更になれば、元の処理の流れも修正をしなきゃいけない。
計算ロジックを修正するときも、足し算割り算どちらにも関わらずこのクラスの書き換えが必要。
何をするにもCalc課長の重い腰を上げて頂く必要があるのだ。
=依存性が強いとはこういうことか!
じゃあ、DIっぽくしてみよう。
「依存性の注入」的なものである。
そもそも、Calcクラスの役割は「計算する」という概念なわけで、
「何々の計算をする」という具体的な所まで包括するといろいろ詰め込みすぎてしまう。
いろんな用途で編集されうるクラスになってしまうということだ。
なので、シンプルに分けていくことにする。
Calc課長しかいろいろできないのは困るので、
「計算する!」というGoサイン出しまでを受け持ってもらい、
「何々の計算をする!」という細かい話は、部下の「モジュール」に分けてそれぞれに依存していこう。
*/
// 「何々の計算をする」にあたる、計算モジュールの実装フォーマット(interface)だよ。
// これを土台に、足し算や引き算を作って、CalcDIに「注入」するよ。
interface CalcModule
{
// 計算モジュールには、とにかく「計算結果をくれ」というメソッドだけは必ず実装してね。
// CalcDI課長が必ず呼ぶよ。
public function getResult($left, $right);
}
// 計算モジュール「足し算」だよ
class CalcAdd implements CalcModule
{
public function getResult($left, $right)
{
return $left + $right;
}
}
// 計算モジュール「割り算」だよ
class CalcDiv implements CalcModule
{
public function getResult($left, $right)
{
return $left / $right;
}
}
// 計算をするクラスがDIっぽくなったよ。
// CalcさんからCalcDIさんに進化した!(実際はスーパー社員からハンコ押し係に格下げ)
// 計算部分は「モジュール」として別のクラスに分けていくよ。
class CalcDI
{
// とにかく、「計算する!」はこれだけだ!
// 計算を実行するときは常にこれを呼ぶだけでいいよ。
// その代わり、$moduleに「何々の計算をする」にあたるモジュールをセットしてね。
// あとCalcModuleの枠に従ってない部下は受け付けないからね!
public function exec(CalcModule $module, $left, $right)
{
// 計算結果を返すね
return $module->getResult($left, $right);
}
}
// では、CalcDI版で足し算をしよう。
$method = 'Add'; // 足し算をしよう
$left = 10; // 左辺は10
$right = 5; // 右辺は5としよう
// 場合によって「何々の計算をする」部分だけを取り分けよう。
if ($method === 'Add') {
$module = new CalcAdd;
} elseif ($method == 'Div') {
$module = new CalcDiv;
}
// さあ計算だ
$calc = new CalcDI;
// 「計算する!」をひたすら叫ぶだけのCalcDIさん
$answer = $calc->exec($module, $left, $right);
// $answerは15だった!
/*
これでもうCalcDI課長は全体の処理で口火を切る「計算をする!」を叫ぶだけの係になり、
ごちゃごちゃ触れられる機会が激減した事が分かった。
計算の種類を増やしたり、計算の内容を変更するときは
それぞれのモジュールを調達したり編集するだけでよくなった。
ただ、まだモジュールの生成に分岐が入っていて実装側はだるいままである。
依頼者は、課長に仕事を依頼する前に望む処理ができる社員を自分で引っ張ってこなければならないのである。
ではここで、やりたいことを伝えれば勝手にモジュールを取ってきてくれる
Factory主任にお出ましいただこう
Factory主任「望みを言え!!さすれば適切な社員をアサインしてやる!」
*/
// ----------------------
// Factory主任だよ。計算モジュールをよしなに取ってくるすごいやつだよ
class CalcModuleFactory
{
// 計算したい種類を教えてくれ!
public function make($method)
{
// その種類なら、計算モジュールの名前はこれのはずだ!
$moduleName = $this->getModuleName($method);
// 一応計算モジュールがあるかどうか事前に調べておこう!
$this->_checkModule($moduleName);
// 計算モジュールが居たぞ受け取れ!!
return new $moduleName;
}
public function getModuleName($method)
{
return 'Calc'.$method;
}
protected function _checkModule($moduleName)
{
if (!class_exists($moduleName)) {
throw new Exception('計算の種類:'.$moduleName.'は未実装のようだ!');
}
}
}
// ではFactory主任に助けてもらって足し算を。
$method = 'Add';
$left = 10; // 左辺
$right = 5; // 右辺
// 分岐もモジュール探しも全部Factory主任にお任せだ
$factory = new CalcModuleFactory;
$module = $factory->make($method);
// ささっと計算!
$calc = new CalcDI;
$answer = $calc->exec($module, $left, $right);
// $answerは15だった!
/*
すばらしい。
これでもう、計算の種類を追加するときはモジュールを作るだけで良くなった。
他に触るべき処理もなくなってしまった。
CalcDI課長はモジュールと左辺と右辺をもらって「計算する!」を叫ぶだけであり、
渡すモジュールはFactory主任が勝手に連れてきてくれるし、
具体的な計算処理であるモジュールたちはinterfaceの秩序のもと足並みを揃えてお行儀良くしながら、
自分の処理に集中しているからである。
結局メインの処理は「目的(やりたい事)」と「材料(左辺と右辺)」を用意するだけで、
もう何も弄らなくて良くなってしまった。
やりたい事が増えても、モジュールを追加(スペシャリスト社員を雇用)するだけでいいのである。
以上で、DIの良さを実感し、なんとなくわかったつもりになれた。
なお、LaravelはDIの概念を掲げてソースを構築しているので、とても勉強になる。
自分も綺麗な実装ができるように日々精進する次第である。
以上でDIってなんだろう?は終了です。
p.s.
これだけ整頓されているとワンライナー化してドヤ顔することもできるぞ!
(ワンライナーは独りよがりにならない範囲で計画的に!)
*/
$answer = (new CalcDI)->exec((new CalcModuleFactory)->make($method), $left, $right);
PR
この記事にコメントする
カレンダー
最新記事
(05/29)
(04/24)
(04/24)
(02/07)
(07/26)