【Unity】【DIコンテナ】セッターインジェクションとコンストラクタインジェクション
- 2009.02.26 Thursday
- 22:55
そろそろUnityもセッターインジェクションやらコンストラクタインジェクションの話に入りそうです。その前にTypeとNameの関係を間違って紹介してしまったので修正しないといけませんがー。
今回は設計に近い実装の話。
シングルトンを前提としてDIコンテナ上でロジックオブジェクトを生成する場合、コンストラクタインジェクションを用いる方が望ましいといわれています。南無南無。でも、実際にコーディングしてみると、プログラマにコーディング規約などでちょっとした縛りを設ければ、セッターインジェクションの方がはるかにコーディングがしやすくなります。これは単なる実感で、確かに「望ましい」けどセッターインジェクションの方がいいなぁーと思えます。
たとえば、下記のようにP1プロパティにセッターインジェクションを用いる場合はセッターとなるプロパティのsetterはDIコンテナから見えるようにpublicで公開する必要があります。
public class A : IA
{
public IB P1 { private get; set; }
public void Method() {...}
}
さて、DIコンテナが生成したAオブジェクトはシングルトンなのでしょうか?私はシングルトンの定義をはっきりと明言するスキルはありませんが、複数のユーザが使用するシングルトンで、かつ、ユーザがいつでもシングルトンを使用できる場合は、状態を持たせてはいけないという事は、はっきりといえます。しかし、セッターインジェクションの場合、コンストラクタの後にDIコンテナがセッターインジェクションを実行するまではP1はnullなわけですから思いっきり変化するフィールド、状態を持っていることになります。また、DIコンテナでなくてもAオブジェクトはP1プロパティのセッターを公開しているわけですから、第三者が意図的に値を変更できます。前者はおそらくDIコンテナがうまくかわしてくれると思いますが、後者はプログラマのアウチなミスで人為的に起こる可能性があります。
では、理想的に書くにはどうするか!?
public class A : IA
{
private readonly IB p1;
public A(IB p1)
{
this.p1 = p1;
}
public void Method() {...}
}
これでp1の値を買い替えられえる心配もなく、このオブジェクトのコンストラクタが終われば必ずp1は不変な値を持つことになります。これは言語的な縛りでさわやかシングルトンを提供しているので、使う側も安心、安心です。ただし、コンストラクタインジェクションでフィールドの値を設定するのは結構面倒です。さらに、セッターインジェクションより間違えやすいです。セッタープロパティを外部で書き換えるのと、設定ファイルや属性の書き間違え、どっちが起こりやすく、どっちが発見しにくいか・・・統計的な情報は何ひとつありませんが、経験則から言うとプログラマはコードを書くのがお仕事ですから、自分が書いたコードに間違いがあるときすぐに発見できます。そもそも、DIコンテナ用にプロパティは書き換えないというルールで縛られているため、書き換える動機を与えません。逆に、設定というは結構間違いやすいですよね。よね?よね?なので、理想と現実のトレードオフにかければおのずと結論がでるわけです。
こんな感じでセッターインジェクションが好まれるわけです。南無南無。
よし、これで説明すればうまくいけそうだ!
今回は設計に近い実装の話。
シングルトンを前提としてDIコンテナ上でロジックオブジェクトを生成する場合、コンストラクタインジェクションを用いる方が望ましいといわれています。南無南無。でも、実際にコーディングしてみると、プログラマにコーディング規約などでちょっとした縛りを設ければ、セッターインジェクションの方がはるかにコーディングがしやすくなります。これは単なる実感で、確かに「望ましい」けどセッターインジェクションの方がいいなぁーと思えます。
たとえば、下記のようにP1プロパティにセッターインジェクションを用いる場合はセッターとなるプロパティのsetterはDIコンテナから見えるようにpublicで公開する必要があります。
public class A : IA
{
public IB P1 { private get; set; }
public void Method() {...}
}
さて、DIコンテナが生成したAオブジェクトはシングルトンなのでしょうか?私はシングルトンの定義をはっきりと明言するスキルはありませんが、複数のユーザが使用するシングルトンで、かつ、ユーザがいつでもシングルトンを使用できる場合は、状態を持たせてはいけないという事は、はっきりといえます。しかし、セッターインジェクションの場合、コンストラクタの後にDIコンテナがセッターインジェクションを実行するまではP1はnullなわけですから思いっきり変化するフィールド、状態を持っていることになります。また、DIコンテナでなくてもAオブジェクトはP1プロパティのセッターを公開しているわけですから、第三者が意図的に値を変更できます。前者はおそらくDIコンテナがうまくかわしてくれると思いますが、後者はプログラマのアウチなミスで人為的に起こる可能性があります。
では、理想的に書くにはどうするか!?
public class A : IA
{
private readonly IB p1;
public A(IB p1)
{
this.p1 = p1;
}
public void Method() {...}
}
これでp1の値を買い替えられえる心配もなく、このオブジェクトのコンストラクタが終われば必ずp1は不変な値を持つことになります。これは言語的な縛りでさわやかシングルトンを提供しているので、使う側も安心、安心です。ただし、コンストラクタインジェクションでフィールドの値を設定するのは結構面倒です。さらに、セッターインジェクションより間違えやすいです。セッタープロパティを外部で書き換えるのと、設定ファイルや属性の書き間違え、どっちが起こりやすく、どっちが発見しにくいか・・・統計的な情報は何ひとつありませんが、経験則から言うとプログラマはコードを書くのがお仕事ですから、自分が書いたコードに間違いがあるときすぐに発見できます。そもそも、DIコンテナ用にプロパティは書き換えないというルールで縛られているため、書き換える動機を与えません。逆に、設定というは結構間違いやすいですよね。よね?よね?なので、理想と現実のトレードオフにかければおのずと結論がでるわけです。
こんな感じでセッターインジェクションが好まれるわけです。南無南無。
よし、これで説明すればうまくいけそうだ!