Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/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 Guice辅助注入过度使用替代方案、依赖注入与非DI构造函数_Java_Oop_Dependency Injection_Guice - Fatal编程技术网

Java Guice辅助注入过度使用替代方案、依赖注入与非DI构造函数

Java Guice辅助注入过度使用替代方案、依赖注入与非DI构造函数,java,oop,dependency-injection,guice,Java,Oop,Dependency Injection,Guice,我喜欢在构造函数中传递运行时依赖项的主要原因是: 它使依赖性成为必需的 它提供了设置实例变量的中心位置 将依赖项设置为实例变量可防止 必须在类中从一个方法传递到另一个方法,或者传递两次或更多 到两个或多个公共方法 这让我在使用Guice时使用了很多辅助注射。与不使用DI相比,这会创建额外的代码,因此阅读如下内容: 似乎大多数人不会使用辅助注入在构造函数中传递运行时(派生的,启动时不可用)依赖项,而是在单个方法中传递它们。对于上面stackoverflow文章中给出的简单类来说,这很好,因为只有

我喜欢在构造函数中传递运行时依赖项的主要原因是:

  • 它使依赖性成为必需的
  • 它提供了设置实例变量的中心位置
  • 将依赖项设置为实例变量可防止 必须在类中从一个方法传递到另一个方法,或者传递两次或更多 到两个或多个公共方法
  • 这让我在使用Guice时使用了很多辅助注射。与不使用DI相比,这会创建额外的代码,因此阅读如下内容:

    似乎大多数人不会使用辅助注入在构造函数中传递运行时(派生的,启动时不可用)依赖项,而是在单个方法中传递它们。对于上面stackoverflow文章中给出的简单类来说,这很好,因为只有一个方法依赖于依赖项:

    public class SomeClass {
        @Inject
        SomeClass(...) {
            ...
        }
    
        public void doWork(int s) { /* use s */ ... }
    }
    
    但是如果这个类有很多使用依赖关系的方法呢?您是否将它从公共方法传递到私有方法,并要求在所有公共方法上传递它? 例如:

    public class SomeClass {
        @Inject
        SomeClass(...) {
            ...
        }
    
        public void doWork(int s) { 
         /*some code */
         someOtherMethod(s);
         anotherMethod(s);  
    
        }
        //any private method that needs it gets it passed in as a param
        private void someOtherMethod(int s)...
        private void anotherMethod(int s)...
    
        //require it passed in all public methods that need it
        public void anotherPublic(int s){
          someOtherMethod(s);
        }
    }
    
    与使用构造函数不同,这增加了一点额外的代码,如下所示:

    public class SomeClass {
        private int s;
        SomeClass(int s) {
            this.s = s;
        }
    
        public void doWork() { 
         someOtherMethod();
         anotherMethod();  
    
        }
        private void someOtherMethod()...
        private void anotherMethod()...
    
        public void anotherPublic(){}
    }
    
    或者您会像这样从服务方法设置实例变量吗

    public class SomeClass {
        Integer s;
        @Inject
        SomeClass(...) {
            ...
        }
    
        public void doWork(Integer s) { 
         /***set instance var this time***/
          this.s = s;
         someOtherMethod();
         anotherMethod();  
    
        }
        private void someOtherMethod()...
        private void anotherMethod()...
    
        public void anotherPublicMethod(){
         if(s==null){ //check if s was set already
             throw new IllegalStateException();
          }else{
          /* do something else */
          }
        }
    
    
    }
    
    或者将依赖项作为参数传递到另一个公共方法中,并在那里设置实例变量?例如:

    public class SomeClass {
        @Inject
        SomeClass(...) {
            ...
        }
    
        public void doWork(Integer s) { 
         /***set instance var this time***/
          this.s = s;
         someOtherMethod();
         anotherMethod();  
    
        }
        private void someOtherMethod()...
        private void anotherMethod()...
    
        public void anotherPublicMethod(Integer s){
           this.s = s;
          /* do something else */
        }
    
    
    }
    
    因此,我认为将参数从一个方法传递到另一个方法或抛出非法状态异常来检查它与使用普通构造函数相比并不理想,但显然任何框架/模式都有其优点/缺点

    如果我只是没有以理想的方式分离我的对象,请告诉我您使用的一些指导原则,即“我每个服务类只使用一个公共方法,请参阅这本书或关于它的帖子:…”


    在上述情况下,你们会怎么做?

    在问题中,你们明确了使用辅助注入的一些重要原因:它确保对象实例只以完全初始化的状态存在,保持依赖关系在一起,并且使对象的公共接口不必在每个方法中都需要可预测的参数

    除了你提到的以外,我真的没有其他选择可以补充:

    • 为该依赖项添加setter方法,可能需要IllegalStateException检查或良好的默认值
    • 使用相同的IllegalStateException检查创建
      初始化(int s)
      伪构造函数方法
    • 在单个方法中接受参数
    • 用自定义工厂替换FactoryModuleBuilder样板文件,从而创建更多您试图避免的额外样板文件
    我最喜欢的是两种方法,一种是辅助注入,另一种是在每个方法中获取参数,这主要是因为它们都使对象始终处于可预测、可用的状态。我在它们之间的决定取决于对象应该携带何种状态,该状态是否可变,以及我希望如何控制实例。对于
    Car.licensePlateNumber
    ,车牌号可能会随车辆实例而变化;每辆车都有一个车牌号(在本例中)永远不会改变,没有车牌号的车是无效的,因此它应该是一个构造函数参数。相反,
    Repository
    可能经常在其所有方法中采用相同的
    T
    实例,但无论传入哪个实例,存储库仍然是一个存储库,您可能希望能够自由地重用该实例,而无需为每个
    T
    创建新实例(这可能与辅助注入有关)。这两种设计都是有效的,并且每一种都是针对特定情况的最佳设计

    记住:

    /** In module: install(new FactoryModuleBuilder().build(SomeClass.Factory.class)); */
    public class SomeClass {
      public interface Factory {
        SomeClass create(int s);
      }
    
      private final int s;
    
      @Inject
      SomeClass(/* ..., */ @Assisted int s) {
        this.s = s;
      }
    
      public void doWork() { /* ... */ }
    }