依赖注入:如何访问执行命令的相应ProductView?

问题描述

我想为每个产品视图执行命令。考虑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);
}

但是,Command Patternexecute()中没有参数。我还在某处看到添加参数是一种反模式。

当然,命令很简单。假设该命令也具有其他依赖项,例如Services等。

有没有一种方法可以实现?也许我做错了,可能是整个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),在AssistedInject中还有一个额外的ProductView,这一事实也使您感到有些恼火。 / p>

在此示例中,按我使用Guice 3的方式。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...