문제

If I want to write testable Code in Java and decided to use a dependency injection pattern to be able to mock my dependencys in the test environment.

Normally I use this pattern in ABAP OO and don't know exactly the best way to achieve the same thing in Java.

Here is what I do in ABAP OO: I only implement against interfaces and make sure to be able to inject the interfaces from the outside. The instantiation happens in the constructor. Or if a method needs to instantiate something I add an optional parameter to inject the dependency.

Here is an example:

CLASS cl_foo DEFINITION.
  PRIVATE SECTION.
    DATA: gr_dependency TYPE REF to if_dependency. "if_dependency is an interface

  PUBLIC SECTION.
    METHODS: constructor IMPORTING iv_bar        TYPE string, "this String makes it complicated in the Java world
                                   ir_dependency TYPE REF TO if_dependency OPTIONAL.

    "CLASS-METHODS: create_instance....
ENDCLASS.

CLASS cl_foo IMPLEMENTATION.
   METHOD constructor.
     IF ir_dependency IS BOUND.
       gr_dependency = ir_dependency.
     ELSE.
       CREATE OBJECT gr_dependency TYPE cl_dependency_implementation EXPORTING iv_bar.
     ENDIF.
   ENDMETHOD.
ENDCLASS.

But how do I achive the same thing in Java? There are no optinal parameters. Lets say I do something like this:

public class Foo {
  private Dependency dependency;

  public Foo(String bar, Dependency dependency) {
    if(dependency == null) {
      this.dependency = new DependencyImplementation(bar);
    }
  }

  //public static Foo createInstance....
}

This is nearly the same behavior (except that "IS BOUND" is different than "== null"). However this does not make it clear, that you don't have to provide an implementation for the interface Dependency. Also if I need references to other classes within Foo I would have to rewrite everything location that instantiates Foo.

도움이 되었습니까?

해결책

Most of the time, when I'm writing Java code, I setup the dependency externally and don't give classes a default if it is null. Instead, if it's null, I throw an IllegalArgumentException to force the value to be set. Generally, I do something like the following:

public class Foo {
    private final Dependency dependency;

    public Foo(Dependency dependency) {
        if(dependency == null) {
            throw new IllegalArgumentException("dependency must be set message.");
        }
        this.dependency = dependency;
    }

// the rest of the code here.
}

With the variable set to final, it will force the value to be set in the constructor, and by throwing an exception, if the developer attempts to pass null, you will help the programmer help to not miss this requirement quickly, rather than a null pointer exception later down the road. If you are using something like spring with an application context XML file to do dependency injection, then this will also help you to track down misspellings or other problems in the xml file, since it will immediately fail, if you fail to provide the parameter.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top