2012年5月7日月曜日

Dependency Injection とリソース指向について

GW最後の夜、ストレッチをしながらDependency Injection(DI)について考えてみた。DIについて調べ始めてまだ3ヶ月の新人なので、未だによく分からないことだらけだが。

DIってリソース指向と似ているのでは?

と思った気がした。
生成するオブジェクトをリソースとして捉えると、
  1. リソース(オブジェクト)の生成
  2. リソースの操作(依存性の注入)
という手順が成立する。

リソースの操作っていうのは、要するに設定の代入と依存性の注入になる。

そこで、さらに手順を細分化してみると

  1. 生成するオブジェクトを特定する
    new、Singleton、staticなど生成方法を含めて一意に特定する
  2. 設定の注入
    オブジェクトにconfigを代入する
  3. 依存性の注入
    任意のオブジェクトを注入可能とする

という手順になるのかな。

◆ オブジェクトを特定するDIN表記

まずはオブジェクトを特定する記述について考えてみる。
こんな感じかな。
['DIN' => [ $className, $type, $idName] ]
ここで
$classNameは生成するクラス名。
$typeはnew、get、static、のどれか。意味は明白だよね。
$idNameは前に生成したオブジェクトを指定するID名。省略可。英数字ならOKとか。

ちなみにDINはDependency Injection Notationの略(笑
で、DIN表記と呼んでみよう。

◆ 設定の注入

さっき作ったオブジェクトに対して、設定を注入する。

['DIN' => [ $className, $type, $idName],
'config' => [ 'A' => 'a', 'B' => 'b', ] ]

と表現できるでしょう。

◆ 依存性の注入

他のオブジェクトをDIN使って表しておいて、依存性を注入。


['DIN' => [ $className, $type, $idName],
'config' => [ 'A' => 'a', 'B' => 'b', ]
'inject' => [
    'name1' => [ 'class1', 'get', 'test' ],
    'name2' => [ 'class2', 'new' ],
  ]
]
これで、DIN表記を導入したメリットが見えるのでは。

必ずしもnewしたオブジェクトを代入する必要はなくて、get(singleton)で作ったオブジェクトを使うことができる。あるいは、複数のオブジェクトで共通したオブジェクトに依存する、という場合もあろう。


◆ PHPでの実装を想像してみる

DIN表記は、こうだよね。
$di->din( 'className', 'new' );
$di->din( 'className', 'get' );
あるいは
$di->din( [ 'className', 'get', 'test' ] );
$di->din( [ 'className', 'static' ] );
設定を注入してみよう。
( Di::start() )->din( 'className', 'new' )->config( $config );
とか格好良くない?

で、依存性を注入。
( Di::start() )->din( 'className', 'get', 'test' )
->config( $config )
->inject( 'loader', [ 'myLoader', 'new', '1' ] )
->inject( 'loader2', [ 'yourLoader', 'get' ] );
さらに
( Di::continue() )->din( 'className', 'get', 'main' )
->config( $config )
->inject( 'loader', [ 'myLoader', 'new', '1' ] )
->inject( 'loader2', [ 'myLoader', 'new', '1' ] );
と別のオブジェクトも続けて生成できたら、便利かなぁ?

あ、まだオブジェクトを入手してない。
( Di::continue() )->forge()
->obtain( $obj1, [ 'className', 'get', 'test' ] )
->obtain( $obj2, [ 'className', 'get', 'main'' ] )
->saveAs( 'myTest' );
設定を保存できたりして。
で、いつでも呼び出せる。
( Di::start() )->forge( 'myTest' )
->...


う~ん。
全部を実装すると大変そうだ。

特に最後の設定の保存あたり。多分このAPIでは使えない気がする。
たとえば、注入されるオブジェクトを保存した設定で生成したい、という場合に対応できない。また生成されるオブジェクトの性質が一定になってしまう。常にnewとか。ちょっと使い勝手が悪そうだ。

それとデフォルトの依存性を誰が管理するか、決めないと。
コンテナ側でデフォルトは持たない、設定の保存などはコンテナの責任、として
どういうAPIで実装すると分かりやすいのか?


まぁGWの夜の夢ということですが、
実際に実装しないとDIとは何かすら分からない状態なので、
もう少し調べてみてから実装してみよう。

0 件のコメント: