inversion-of-control で欠けている部分は、アプリケーション レイヤーがコンストラクターを直接呼び出さないことです。ファクトリー (IoC コンテナー) を使用してコンストラクター パラメーターを設定します。
使用するツールが何であれ、guice / spring / picocontainer / singleton-factories の場合、アプリケーション コードは次のようになります。
@Controller
class MyController {
@Resource // Some container knows about this annotation and wires you in
MyBusinessLogic myBusinessLogic;
@RequestMethod("/foo/bar.*")
public MyWebResponse doService(Response resp, long id, String val) {
boolean worked = myBusinessLogic.manipulatevalue(id, val);
return new MyWebResponse(worked);
}
}
myBusinessLogic は、Java の @Resource、MyBusinessLogicFactory.getMyBusinessLogic()、guice.get(MyBusinessLogic.class) など、いくつかの方法で登録できることに注意してください。
貧乏人の解決策は次のとおりです。
package foo;
class MyBusinessLogicFactory {
static volatile MyBusinessLogic instance; // package-scoped so unit tests can override
public static MyBusinessLogic getInstance() {
if (instance == null) {
synchronized(MyBusinessLogicFactory.class) {
instance = new MyBusinessLogic(MyDatabaseLayerFactory.getInstance());
}
}
return instance;
}
}
// repeat with MyDatabaseLayerFactory
上記のシングルトン モデルにはスコープがないため、使用しないことを強くお勧めします。上記をコンテキスト内にラップできます-次のように
class Context {
Map<Class,Object> class2Instance = new ConcurrentHashMap<>();
public <T> T getInstance(Class<T> clazz) {
Object o = class2Instance.get(clazz);
if (o == null) {
synchronized(this) {
o = class2Instance.get(clazz);
if (o != null) return (T)o;
o = transitivelyLoadInstance(clazz); // details not shown
for (Class c : loadClassTree(clazz)) { // details not shown
class2Instance.put(c, o);
}
}
}
return (T)o;
}
...
}
しかし、その時点で、picocontainer、guice、および spring は、上記の SOOO の複雑さをはるかにうまく解決できます。
さらに、Java 6 アノテーションを尊重するスプリングのようなものは、コンストラクター注入以外のことを実行できることを意味します。これは、同じ基本データ型 (文字列など) の構成アイテムが複数ある場合に非常に役立ちます。