代码之家  ›  专栏  ›  技术社区  ›  Dan Bryant

这种依赖注入的设计容易理解吗?

  •  3
  • Dan Bryant  · 技术社区  · 15 年前

    我在一个有大量现有代码库的项目中工作,我的任务是对其中的一小部分进行重新设计。现有的代码库没有太多的单元测试,但我希望至少我正在研究的部分有一整套具有良好代码覆盖率的单元测试。

    1. 我提取了我的“协调器”类所依赖的所有非平凡类的接口。其他开发人员勉强同意了这一点,只是有些小小的抱怨。

    2. 我修改了coordinator类,以便只引用其操作的接口。

    .

    public sealed class Coordinator
    {
        private IFactory _factory;
    
        public Coordinator(int param)
            : this(param, new StandardFactory())
        {            
        }
    
        public Coordinator(int param, IFactory factory)
        {
            _factory = factory;
            //Factory used here and elsewhere...
        }
    
        public interface IFactory
        {
            IClassA BuildClassA();
    
            IClassB BuildClassB(string param);
    
            IClassC BuildClassC();
        }
    
        private sealed class StandardFactory : IFactory
        {
            public IClassA BuildClassA()
            {
                return new ClassA();   
            }
    
            public IClassB BuildClassB(string param)
            {
                return new ClassB(param);
            }
    
            public IClassC BuildClassC()
            {
                return new ClassC();
            }
        }
    }
    

    这允许注入stubbed工厂来返回模拟的依赖项以进行单元测试。我担心的是,这也意味着这个类的任何用户都可以提供自己的工厂来改变这个类的操作方式,这并不是真正的意图。这个构造函数纯粹是用于单元测试的,但是它的副作用是意味着需要额外的扩展性。在我使用的其他类中,我通常看不到这种模式,这让我怀疑是否过于复杂,是否有更好的方法来实现所需的隔离。


    注意:代码格式有点奇怪,所以我为上面糟糕的格式道歉。不知道为什么它不能让我正确格式化它。

    2 回复  |  直到 15 年前
        1
  •  3
  •   Mark Seemann    15 年前

    建议的设计是 施工人员受伤 私生子注射 . 在绿地的情况下,我认为私生子注入是一种反模式,但在你描述的棕地情况下,这是一种很好的妥协。

    您不应该真正关心协调器类的隐含可扩展性。正确完成, testability is extensibility ,因此理想情况下,注入的IFactory应该表示一个支持可变性的适当域概念。我理解,当您从遗留代码重构时,很难/不可能一下子实现这一点,但这正是您的代码库应该朝着的方向发展。

    提取 对于接口,它们可能不太可能将IFactory构造函数参数解释为扩展点。

        2
  •  2
  •   PatrickSteele    15 年前

    您可能需要考虑使构造函数接受 IFactory 内部——这将防止程序集外部的其他用户“扩展”您的协调器。然后使用 InternalsVisibleTo 属性将其仅公开给单元测试。

    推荐文章