[英]Dependency Injection: How to get access to the corresponding ProductView that executes the Command?
我想為每個產品視圖執行命令。 考慮 10 個產品視圖,每個視圖都可以執行PrintProductViewCommand
。 此命令接收構造函數ProductView
並打印其名稱。 由於它@Inject
,每次創建命令時容器都會創建一個新的ProductView。 以下示例顯示了我想要做什么:
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(ProductView.class);
bind(CommandExecutor.class);
bind(PrintProductViewNameCommand.class);
install(new FactoryModuleBuilder().implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
}
});
List<ProductView> productViews = new ArrayList<>();
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + String.valueOf(i)));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private static interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name; //simulate a property
private CommandExecutor executor;
public ProductView() {
//Guice throws exception when this is missing
//Probably because it is being asked in PrintProductViewCommand
}
@AssistedInject
public ProductView(@Assisted String name, CommandExecutor executor) {
this.name = name;
this.executor = executor;
}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(PrintProductViewNameCommand.class);
}
}
@Singleton
private static class CommandExecutor {
@Inject
private Injector injector;
public void execute(Class<? extends Command> cmdType) {
injector.getInstance(cmdType).execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private ProductView view;
@Inject
public PrintProductViewNameCommand(ProductView view) {
this.view = view;
}
@Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
如果我向 Command 接口添加一個參數並使其成為Command<T>
,這個問題就解決了。 然后CommandExecutor
將有這個方法:
public <T> void execute(Class<? extends Command<T>> cmdType, T parameter) {
injector.getInstance(cmdType).execute(parameter);
}
所以,我的PrintProductViewNameCommand
現在是class PrintProductViewNameCommand implements Command<ProductView>
,在產品視圖中:
public void print() {
executor.execute(PrintProductViewNameCommand.class,this);
}
但是,命令模式在execute()
中沒有參數。 我還在某處看到添加參數是一種反模式。
當然,命令很簡單。 假設該命令也有其他依賴項,如服務等。
有什么辦法可以實現嗎? 也許我做錯了什么,可能是整個 DI 情況。
當不使用依賴注入時,我會做這樣的事情:
ProductView view = new ProductView();
Command command = new PrintProductViewNameCommand(view);
view.setPrintCommand(command);
但是如何使用 DI 呢?
所以這是有效的,雖然我不確定它是否是你想要做的 100%。
public class InjectionTest {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(CommandExecutor.class);
bind(ProductView.class);
install(new FactoryModuleBuilder()
.implement(ProductView.class, ProductView.class)
.build(ProductViewFactory.class));
install(new FactoryModuleBuilder()
.implement(PrintProductViewNameCommand.class, PrintProductViewNameCommand.class)
.build(PrintProductViewNameCommand.Factory.class));
}
});
ProductViewFactory factory = injector.getInstance(ProductViewFactory.class);
List<ProductView> productViews = new ArrayList<>();
for (int i = 0; i < 10; i++) {
productViews.add(factory.create("Name: " + i));
}
System.out.println("Done creating");
//Now sometime in future, each product view calls print method
productViews.forEach(ProductView::print);
}
private interface ProductViewFactory {
ProductView create(String name);
}
private static class ProductView {
private String name;
private CommandExecutor executor;
private PrintProductViewNameCommand printProductViewNameCommand;
@AssistedInject
public ProductView(@Assisted String name, PrintProductViewNameCommand.Factory printProductViewNameCommandFactory, CommandExecutor executor) {
this.name = name;
this.executor = executor;
this.printProductViewNameCommand = printProductViewNameCommandFactory.create(this);
}
public ProductView() {}
public String getName() {
return name;
}
//assume some time product view it self calls this method
public void print() {
executor.execute(printProductViewNameCommand);
}
}
@Singleton
private static class CommandExecutor {
public void execute(Command command) {
command.execute();
}
}
private static class PrintProductViewNameCommand implements Command {
private final ProductView view;
@AssistedInject
public PrintProductViewNameCommand(@Assisted ProductView view) {
this.view = view;
}
static interface Factory {
PrintProductViewNameCommand create(ProductView productView);
}
@Override
public void execute() {
//Want to print "Name: something" here
System.out.println(view.getName());
}
}
private static interface Command {
void execute();
}
}
基本上你遇到的是一個循環依賴問題( https://github.com/google/guice/wiki/CyclicDependencies#use-factory-methods-to-tie-two-objects-together )也被激怒了事實上,您在ProductView
中有一個額外的AssistedInject
。
順便說一下,我在此示例中使用的是 Guice 3。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.