Мне кажется, вам нужна область для каждого экземпляра RootObject
и всех его зависимостей.
В Guice вы можете создать пользовательскую область, скажем @ObjectScoped
, например:
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@ScopeAnnotation
public @interface ObjectScoped {}
Теперь просто поместите RootObject
, A
, B
и D
в эту область:
@ObjectScoped
public class RootObject {
private A a;
private B b;
@Inject
public RootObject(A a, B b) {
this.a = a;
this.b = b;
}
public A getA() {
return a;
}
public B getB() {
return b;
}
}
@ObjectScoped
public class A {
private D d;
@Inject
public A(D d) {
this.d = d;
}
public D getD() {
return d;
}
}
// The same for B and D
Теперь каждый RootObject
имеет свою область видимости. Вы можете реализовать это как простой HashMap
:
public class ObjectScope {
private Map<Key<?>,Object> store = new HashMap<Key<?>,Object>();
@SuppressWarnings("unchecked")
public <T> T get(Key<T> key) {
return (T)store.get(key);
}
public <T> void set(Key<T> key, T instance) {
store.put(key, instance);
}
}
Для интеграции этих областей с Guice вам потребуется реализация com.google.inject.Scope
, позволяющая переключать области и соответствующую проводку в Module
.
public class GuiceObjectScope implements Scope {
// Make this a ThreadLocal for multithreading.
private ObjectScope current = null;
@Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
return new Provider<T>() {
@Override
public T get() {
// Lookup instance
T instance = current.get(key);
if (instance==null) {
// Create instance
instance = unscoped.get();
current.set(key, instance);
}
return instance;
}
};
}
public void enter(ObjectScope scope) {
current = scope;
}
public void leave() {
current = null;
}
}
public class ExampleModule extends AbstractModule {
private GuiceObjectScope objectScope = new GuiceObjectScope();
@Override
protected void configure() {
bindScope(ObjectScoped.class, objectScope);
// your bindings
}
public GuiceObjectScope getObjectScope() {
return objectScope;
}
}
Инициализируйте вашу программу так:
ExampleModule module = new ExampleModule();
Injector injector = Guice.createInjector(module);
GuiceObjectScope objectScope = module.getObjectScope();
Создайте первый экземпляр RootObject
и соответствующую ему область:
ObjectScope obj1 = new ObjectScope();
objectScope.enter(obj1);
RootObject rootObject1 = injector.getInstance(RootObject.class);
objectScope.leave();
Просто переключите область видимости для второй группы объектов:
ObjectScope obj2 = new ObjectScope();
objectScope.enter(obj2);
RootObject rootObject2 = injector.getInstance(RootObject.class);
objectScope.leave();
Проверьте, удовлетворены ли ваши требования:
assert rootObject1 != rootObject2;
assert rootObject1.getA() != rootObject2.getA();
assert rootObject1.getA().getD() == rootObject1.getB().getD();
assert rootObject1.getA().getD() != rootObject2.getB().getD();
Для работы с группой объектов просто введите ее область и используйте инжектор:
objectScope.enter(obj1);
B b1 = injector.getInstance(B.class);
objectScope.leave();
assert rootObject1.getB() == b1;