依赖注入 – 类是否应该与配置类具有“has-a”关系?

我已经看到一些关于在类中包装一组配置属性的问题,而不是如何实际使用它.给定一个配置类(为简洁省略getter和setter):

class ServiceConfiguration {
    private String foo;     
}

服务类应该直接使用配置吗?

static class SomeServiceB {
    private ServiceConfiguration configuration;

    public SomeServiceB(ServiceConfiguration configuration) {
        this.configuration = configuration;
    }

    public void printIt() {
        System.out.println(configuration.getFoo());
    }
}

或者它应该只关注foo的实际价值?例如:

static class SomeServiceA {
    private String foo;

    public SomeServiceA(String foo) {
        this.foo = foo;
    }

    public void printIt() {
        System.out.println(foo);
    }
}

我认为SomeServiceA是优越的,因为较低的耦合和关注点分离.

解决方法

两种方案都是正确的.重要的是,类只依赖于它实际使用的配置值.

这意味着注入一个包含所有配置值的ApplicationConfiguration对象,或允许访问所有应用程序配置值是一个坏主意,因为这使得不清楚该类实际使用的配置值并推迟配置值的读取可能导致配置错误只是很晚才出现.口头禅是:快速失败.

注入一个封装类所需值的对象通常比在单独的构造函数参数中注入所有这些值更方便.这基本上是Parameter Object refactoring.

将配置值(即使只是一个)包装到参数对象中的另一个好处是,它允许DI容器自动连接此类.当类具有除配置值之外的依赖项时,这尤其有用.例如:

class SomeServiceB {
    public SomeServiceB(IDep1 d1,IDep2 d2,SomeServiceConfig config) {
    }
}

DI容器不能轻易地自动连接原始值,因为字符串和整数等值是不明确的:您可能有多个具有不同含义的值的实例.例如,您可能同时拥有连接字符串和文件路径.两者都是字符串.

尽管使配置对象不可变,但要清楚地表明它们无法更改是很重要的.您通常应该在应用程序启动时构造它们并将它们注册为单例.

相关文章

什么是设计模式一套被反复使用、多数人知晓的、经过分类编目...
单一职责原则定义(Single Responsibility Principle,SRP)...
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强...
适配器模式将一个类的接口转换成客户期望的另一个接口,使得...
策略模式定义了一系列算法族,并封装在类中,它们之间可以互...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,...