减少构造函数参数,同时明确保持服务使用?

时间:2015-09-01 16:23:36

标签: oop design-patterns dependency-injection

我正在使用C#,但我的问题适用于任何OOP语言。

我有许多不同的对象,它们使用一系列服务。我想访问这些服务的方式来满足一些约束,但我正在努力找出一个好的设计。

  • 我希望这些服务的使用是明确的
  • 对象永远不应处于无效状态(服务应在构造时传递)
  • 服务使用应该清晰
  • 代码重复应该是最小的

我认为这些都是很好的目标,但事实证明它们在实践中很难实现。我目前的方法是一种依赖注入手动

class MyObject
{
    // ... 

    public MyObject(IFooService fooService, IBarService barService)
    {
        this.fooService = fooService;
        this.barService = barService;
    }
}

到目前为止一切顺利。但是当我有很多服务依赖项时会发生什么?我有几十个对象,其中一些需要访问许多服务。

我考虑过构建一个“服务容器”对象并将其传递给:

class Services
{
    // ... 

    public IFooService FooService
    {
        get { return this.fooService; } 
    }

    public IBarService BarService
    {
        get { return this.barService; } 
    }

    public Services(IFooService fooService, IBarService barService)
    {
        this.fooService = fooService;
        this.barService = barService;
    }
}

class MyObject
{
    // ...

    public MyObject(Services services)
    {
        this.services = services;
    }
}

这节省了输入,但它模糊了对象实际使用的服务。给定构造函数,MyObject可能会使用任何

  • 避免此问题的常用方法有哪些?
  • 我的问题是否表明更基本的设计问题?
  • 这真的是一个问题吗?我应该放松一些设计目标吗?

3 个答案:

答案 0 :(得分:5)

这可能表明存在两个问题

  1. 要注入的服务太细粒度(例如,如果你有一个服务来创建一个Foo,另一个用来更新一个Foo,另一个用来删除一个Foo),导致很多依赖。< / LI>
  2. 或者更可能的是,使用该服务的对象太粗糙,并且责任太多。例如,如果一半方法使用一组服务而另一半使用另一组服务,那么可能很好地表明该对象可以分为两类。
  3. 无论如何,如果你认为你的课程不是太复杂,你可以阅读,维护和测试它,我不会过多关注依赖的数量。我更喜欢拥有清晰,明确的依赖关系,而不是依赖于作为服务工厂并取决于所有事物的上帝对象。这将损害可测试性和可读性。

答案 1 :(得分:2)

Mark Seemann用解决方案here描述了这个问题。

总结:

  1. 确保您没有违反SRP
  2. 使用聚合服务重构依赖关系 - Facade Service
  3. 它会为您的代码带来另一个抽象,但提取的行为很可能会描述应该分开的域概念。

答案 2 :(得分:1)

  

“我考虑建立一个”服务容器“对象”

就像你已经注意到的那样,只是将问题转移到其他地方,但并没有真正解决它。

有一种类似的设计模式,通常称为"Parameter Object" ......但我不认为它真的适用于此。根据前一句中引用的文章,它只适用于......

  

“......一组特定的参数,往往会一起传递。”

因此,参数对象模式仅适用于您的情况,如果您有多个类都依赖于相同的服务组件组合(如果您的构造函数参数列表非常长,则这种情况不太可能)。

  

“当我有很多服务依赖项时会发生什么?”

如果你有如此多的服务依赖项,你的构造函数参数列表变得笨拙的怪物,那么或许你的类有太多的责任,即尝试做太多事情你应该把它分解成几个小班。

我不记得我在哪里阅读它,我并不是说我完全同意,但是一些聪明的人曾经声称任何对象不应该有超过两个字段/引用其他对象。这只是为了表明有些人非常重视“单一责任原则”并走极端(恕我直言)来实现这一目标。