Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在多模块环境中使用依赖项注入(通过GUI)_Java_Dependency Injection_Structure_Guice - Fatal编程技术网

Java 在多模块环境中使用依赖项注入(通过GUI)

Java 在多模块环境中使用依赖项注入(通过GUI),java,dependency-injection,structure,guice,Java,Dependency Injection,Structure,Guice,我在涉及Guice和避免非Guice单例时遇到了一个小小的难题。考虑一个多模块的项目,它有3个模块:共享,前端< /代码>和后端< /代码>。前端和后端都在共享模块中使用了评测类的实例(该类对方法进行计时,并在整个项目中广泛使用) 几乎每个类都需要使用这个评测实例(包括用户连接时动态创建的用户对象) 如果每个类都需要一个评测类的实例,那么不同的方法都有缺点: 解决方案1(在构造函数中,复制到实例字段): 缺点:您必须在每个构造函数中包含一个分析对象。这很麻烦,而且有点毫无意义。您还必须静态地存储

我在涉及Guice和避免非Guice单例时遇到了一个小小的难题。考虑一个多模块的项目,它有3个模块:<代码>共享<代码>,<代码>前端< /代码>和<代码>后端< /代码>。
前端
后端
都在
共享
模块中使用了
评测
类的实例(该类对方法进行计时,并在整个项目中广泛使用)

几乎每个类都需要使用这个
评测
实例(包括用户连接时动态创建的
用户
对象)

如果每个类都需要一个
评测
类的实例,那么不同的方法都有缺点:

解决方案1(在构造函数中,复制到实例字段):

缺点:您必须在每个构造函数中包含一个
分析
对象。这很麻烦,而且有点毫无意义。您还必须静态地存储Guice的
注入器
(或注入),这样您就可以动态地创建
用户
对象,而不仅仅是在程序首次加载时

解决方案2(仅作为实例字段):

缺点:与上面类似,您必须使用Guice的
Injector
来实例化每个对象。这意味着要动态创建
User
对象,您需要创建
User
对象类中的注入器实例

解决方案3(作为一个(主)类中的静态字段,由我们手动创建)

缺点:与Guice的/依赖项注入建议背道而驰-创建静态访问(通过
应用程序.Profiling.start()
)的单例
评测
对象会破坏Guice的用途吗

解决方案4(作为每个类中的静态字段,由Guice注入)

缺点:同样,这违背了Guice的/依赖项注入建议,因为它是静态注入的。我还必须请求Guice需要将分析器注入的每个类(这也很麻烦)

有没有更好的方法来设计我的项目,避免回到我以前使用的单例设计模式

TL;DR:我希望能够跨每个类访问这个评测实例(每个模块一个),而不必回到单例设计模式


谢谢

实际上,我会使用普通的单例,可能是通过单字段枚举或类似的模式

要了解原因,您应该问这样一个问题:Guice和依赖注入的目的是什么?其目的是分离应用程序的各个部分,以便它们可以独立开发和测试,并集中配置和重新排列。考虑到这一点,您需要权衡耦合成本和解耦成本。这取决于您选择耦合或解耦的对象

在这里,耦合的代价是,如果没有一个真正的评测工作实例,您将无法操作应用程序的任何部分,包括在测试中,包括针对像用户这样的模型对象。因此,如果分析对其环境做出任何假设,例如,高分辨率系统定时调用的可用性,则在不允许禁用分析的情况下,您将无法使用像User这样的类。此外,如果为了测试隔离,您希望您的测试使用一个新的(非单例)评测实例评测,那么您需要单独实现它。然而,如果您的评测类足够轻量级,不会造成巨大负担,那么您仍然可以选择这种方式

解耦的代价是它可以迫使每一个对象都成为一个独立的对象。然后,您就可以在类和测试中替换新的/伪的/伪的评测实现,并重新配置以在不同的容器中使用不同的评测行为,尽管如果您没有理由替代这些实现,这种灵活性可能不会立即带来好处。对于像稍后创建的User这样的类,您需要执行工厂实现,例如通过或提供的实现。(请记住,您可以通过为任何要注入的对象注入
Provider
而不是
T
来创建任意数量的对象,注入Factory实例就像自定义提供者以获取您选择的
get
参数一样。)

关于您的解决方案:

  • 解决方案1和2,每个对象注入:这是一个工厂将发光的地方。(如果有选择的话,我倾向于构造函数注入,所以我会选择解决方案1。)当然,创建新用户的所有东西都需要注入
    User.Factory
    ,因此,这可能会将一个范围严格的项目变成一个将代码库中的每个类都转换为DI的项目,这对于您现在正在尝试的工作来说可能是一个不可接受的成本

    // Nested interface for your Factory:
    public interface Factory { User get(String username); }
    
    // Mark fields that the user provides:
    @Inject public User(Profiling profiling, @Assisted String username) { ... }
    
    // Wire up your Factory in a Module's configure:
    install(new FactoryModuleBuilder().implement(User.Factory.class));
    
    // Now you can create new Users on the fly:
    @Inject User.Factory userFactory;
    User myNewUser = userFactory.get("timothy");
    
  • 解决方案3,请求主保持架的静态注入与我的想法大致相同:对于不是通过依赖项注入创建的对象,请求单个类的静态注入,例如
    ProfilingHolder
    或类似的类。为了灵活性,您甚至可以不给它任何操作行为:

    public class ProfilingHolder {
      // Populate with requestStaticInjection(ProfilingHolder.class).
      @Inject static Profiling profilingInstance;
      private ProfilingHolder() { /* static access only */ }
      public static Profiling getInstance() {
        if (profilingInstance == null) {
          // Run without profiling in isolation and tests.
          return new NoOpProfilingInstance();
        }
        return profilingInstance;
      }
    }
    
    当然,如果您依赖于对VM单例的调用,那么您实际上采用了一种普通的VM全局静态单例模式,只要在可能的情况下使用Guice即可。您可以轻松地改变这种模式,并拥有一个Guice模块
    bind(Profiling.class).toInstance(Profiling.INSTANCE)并获得相同的效果(假设可以在没有Guice的情况下实例化分析)

  • < >强>解决方案4,对于每一个类的请求静态注入是我唯一不考虑的。类的列表太长,并且它们变化的可能性太大
    public static final Profiling PROFILING; // Can also use a get method
    
    public Application() {
        Application.PROFILING = injector.getInstance(Profiling.class)
    }
    
    @Inject
    private static Profiling profiling;
    
    // You need to request every single class:
    // requestStaticInjection(XXXX.class)
    
    // Nested interface for your Factory:
    public interface Factory { User get(String username); }
    
    // Mark fields that the user provides:
    @Inject public User(Profiling profiling, @Assisted String username) { ... }
    
    // Wire up your Factory in a Module's configure:
    install(new FactoryModuleBuilder().implement(User.Factory.class));
    
    // Now you can create new Users on the fly:
    @Inject User.Factory userFactory;
    User myNewUser = userFactory.get("timothy");
    
    public class ProfilingHolder {
      // Populate with requestStaticInjection(ProfilingHolder.class).
      @Inject static Profiling profilingInstance;
      private ProfilingHolder() { /* static access only */ }
      public static Profiling getInstance() {
        if (profilingInstance == null) {
          // Run without profiling in isolation and tests.
          return new NoOpProfilingInstance();
        }
        return profilingInstance;
      }
    }