【发布时间】:2021-02-07 20:16:40
【问题描述】:
我想为每个产品视图执行命令。考虑 10 个产品视图,每个视图都可以执行 PrintProductViewCommand。该命令接受构造函数 ProductView 并打印其名称。由于是@Injectable,所以每次创建命令时容器都会创建一个新的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);
}
但是,Command Pattern 在execute() 中没有参数。我还在某处看到添加参数是一种反模式。
当然,命令很简单。假设该命令也有其他依赖项,例如服务等。
有什么方法可以实现吗?也许我做错了什么,可能是整个 DI 情况。
当不使用依赖注入时,我会这样做:
ProductView view = new ProductView();
Command command = new PrintProductViewNameCommand(view);
view.setPrintCommand(command);
但是如何在使用 DI 时呢?
【问题讨论】:
-
我认为最复杂的可能是对
ProductView和PrintProductViewNameCommand的循环依赖。我知道这是一个玩具示例,但在您的实际应用程序中,PrintProductViewNameCommand是否有必要 100% 了解ProductView? -
@WilliamHammond 是的,它会的。
command依赖于各种服务和视图。将服务传递到视图中是一回事,但我不希望这样。
标签: java dependency-injection guice command-pattern