Use dependency injection instead of hard connections-Chapter 2 Create and Destroy Objects-Effective Java Study Notes 04

The content of the article comes from the book Joshua Bloch-Effective Java (3rd)-2018.chm

Chapter two

Create and unregister objects

Item 5 prefers dependency injection rather than hardwired resources

Prefer dependency injection to hardwiring resources
Many classes depend on one or more underlying resources.
Static tool classes:

// Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {
    private static final Lexicon dictionary = ...;

    private SpellChecker() {} // Noninstantiable

    public static boolean isValid(String word) { ... }
    public static List<String> suggestions(String typo) { ... }
} 

Singleton:

// Inappropriate use of singleton - inflexible & untestable!
public class SpellChecker {
    private final Lexicon dictionary = ...;

    private SpellChecker(...) {}
    public static INSTANCE = new SpellChecker(...);

    public boolean isValid(String word) { ... }
    public List<String> suggestions(String typo) { ... }
} 

Both of these methods are not satisfactory because they assume that only one dictionary is worth using

You can try to make SpellChecker support multiple dictionaries by setting the dictionary field to non-final and adding a method to the existing spell checker to change the dictionary, but this will be awkward, error-prone, and in concurrent settings Not feasible. Static utility classes and singletons are inappropriate for classes whose behavior is parameterized by underlying resources

What is needed is to be able to support multiple instances of the class (SpellChecker in our example), each of which uses the resources required by the client (in our example, a dictionary).

A simple pattern to meet this requirement is to pass resources to the constructor when creating a new instance. This is a form of dependency injection: the dictionary is a dependency of the spelling checker and is injected into the spelling checker when the dictionary is created

// Dependency injection provides flexibility and testability
public class SpellChecker {
    private final Lexicon dictionary;

    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }

    public boolean isValid(String word) { ... }
    public List<String> suggestions(String typo) { ... }
} 

Dependency injection also applies to constructors, static factory methods and generators

A useful variant of the pattern is to pass the resource factory to the constructor. A factory is an object that can be called repeatedly to create an instance of a type. These factories embody the factory method pattern [Gamma95]. The Supplier interface introduced in Java 8 is very suitable for representing factories. The supplier's approach to input should generally use a bounded wildcard type (item 31) to constrain the type parameter of the factory to allow the client to pass in and create any subtype of the factory of the specified type. For example, the following is a method of making mosaics using a factory provided by the customer to produce each tile:

Mosaic create(Supplier<? extends Tile> tileFactory) { ... }

In short, do not use singletons or static tool classes to implement classes that depend on one or more underlying resources. The behavior of these resources will affect the behavior of the class, and do not let the class directly create these resources. Instead, pass the resources or the factory that created them into the constructor (or static factory or generator). This practice, called dependency injection, will greatly improve the flexibility, reusability, and testability of classes.

In summary, do not use a singleton or static utility class to implement a class that depends on one or more underlying resources whose behavior affects that of the class, and do not have the class create these resources directly. Instead, pass the resources, or factories to create them, into the constructor (or static factory or builder). This practice, known as dependency injection, will greatly enhance the flexibility, reusability, and testability of a class.

Guess you like

Origin blog.csdn.net/weixin_43596589/article/details/112561825