Dependency injection 一个班级应该有一个“a”吗;has-a“;与配置类的关系?

Dependency injection 一个班级应该有一个“a”吗;has-a“;与配置类的关系?,dependency-injection,Dependency Injection,我看到了一些关于在类中包装一组配置属性的问题,但没有看到如何实际使用它。给定一个配置类(为了简洁起见,省略了getter和setter): 服务类是否应该直接使用配置 static class SomeServiceB { private ServiceConfiguration configuration; public SomeServiceB(ServiceConfiguration configuration) { this.configuration

我看到了一些关于在类中包装一组配置属性的问题,但没有看到如何实际使用它。给定一个配置类(为了简洁起见,省略了getter和setter):

服务类是否应该直接使用配置

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
对象是一个坏主意,因为这使得不清楚类实际使用的配置值,并且延迟读取配置值可能会导致配置错误只会很晚出现。口头禅是:快速失败

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

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

class SomeServiceB {
    public SomeServiceB(IDep1 d1, IDep2 d2, SomeServiceConfig config) {
    }
} 
基本值不能轻易地由DI容器自动连接,因为像字符串和整数这样的值是模糊的:这些值可能有多个完全不同含义的实例。例如,您可能同时拥有连接字符串和文件路径。两者都是字符串


但重要的是要使配置对象不可变,以便清楚地传达它们不能更改的信息。通常,您应该在应用程序启动时构造它们,并将它们注册为单例。

这是一个公平的问题,但由于它基本上是基于意见的,因此不在讨论范围之内。如果
ServiceConfiguration
是可变的,并且您希望服务反映任何更改,则后者需要手动同步。如果需要访问多个字段,则后者将更加麻烦。如果它只是拉一个单一的不可变值,那么这是一个意见问题。@SeanVanGorder将可变性放在一边,我仍然认为它隔离了变化。假设有几个服务在我的应用程序中使用ServiceConfiguration,而应用程序使用SpringJava配置。因此,在我的Spring配置类中,我有一些方法,比如
@Bean SomeServiceA getA(){return new SomeServiceA(conf.getFoo());}
。如果我要在配置类中重命名getter,那么所有服务类都必须更改,而不仅仅是一个Java配置类。Spring配置类中的
conf.getFoo()
调用以及构造需要此值的服务类的任何其他代码也需要更改。另外,如果您要重命名configuration类中的
foo
字段,您可能还需要重命名service类中的
foo
字段和构造函数参数。我不会在这里标记
java
。这真的没关系。
class SomeServiceB {
    public SomeServiceB(IDep1 d1, IDep2 d2, SomeServiceConfig config) {
    }
}