用依赖注入代替硬连接-第二章创建和销毁对象-Effective Java学习笔记04

文章内容来源于Joshua Bloch - Effective Java (3rd) - 2018.chm一书

第二章

创建和注销对象

Item 5更喜欢依赖注入而不是硬连接资源

Prefer dependency injection to hardwiring resources
很多类依赖于一个或多个底层资源
静态工具类:

// 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) { ... }
} 

单例:

// 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) { ... }
} 

这两种方法都不令人满意,因为它们假设只有一个字典值得使用

您可以尝试让SpellChecker支持多个字典,方法是将dictionary字段设置为非final,并在现有的拼写检查器中添加一个方法来更改字典,但这将很尴尬,容易出错,并且在并发设置中不可行。静态实用程序类和单例对于其行为由底层资源参数化的类是不合适的

所需要的是能够支持类的多个实例(在我们的示例中是SpellChecker),每个实例都使用客户端所需的资源(在我们的示例中是dictionary)。

满足此需求的一个简单模式是在创建新实例时将资源传递给构造函数。这是依赖注入的一种形式:字典是拼写检查器的依赖项,在创建字典时被注入拼写检查器

// 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) { ... }
} 

依赖注入同样适用于构造函数、静态工厂f方法和生成器

模式的一个有用变体是将资源工厂传递给构造函数。工厂是可以重复调用以创建类型实例的对象。这些工厂体现了工厂方法模式[Gamma95]。在Java8中引入的Supplier接口非常适合代表工厂。对输入采用供应商的方法通常应使用有界通配符类型(第31项)约束工厂的类型参数,以允许客户机传入创建指定类型的任何子类型的工厂。例如,以下是一种使用客户提供的工厂制作马赛克的方法,以生产每个瓷砖:

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

总之,不要使用单例或静态工具类来实现依赖于一个或多个底层资源的类,这些资源的行为会影响该类的行为,并且不要让该类直接创建这些资源。相反,将资源或创建它们的工厂传递到构造函数(或静态工厂或生成器)中。这种被称为依赖注入的实践将极大地提高类的灵活性、可复用性和可测试性。

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.

猜你喜欢

转载自blog.csdn.net/weixin_43596589/article/details/112561825