【问题标题】:Are void return methods that change the state of their argument an anti-pattern?改变参数状态的 void 返回方法是反模式吗?
【发布时间】:2013-03-12 13:47:29
【问题描述】:

返回 void 但更改其参数状态(即提供隐藏或隐式返回值)的方法通常是不好的做法吗?

我发现它们很难模拟,这表明它们可能是糟糕设计的标志。

有哪些模式可以避免它们?

一个非常人为的例子:

public interface IMapper
{
    void Map(SourceObject source, TargetObject target);
}

public class ClassUnderTest
{
    private IMapper _mapper;

    public ClassUnderTest(IMapper mapper)
    {
        _mapper = mapper;
    }

    public int SomeOperation()
    {
        var source = new SourceObject();
        var target = new TargetObject();

        _mapper.Map(source, target);

        return target.SomeMappedValue;
    }
}

【问题讨论】:

  • 如何使用 void Initialize() 方法,它返回 void 并且仅用于更改对象状态?还是 void Fill(object o) 对对象 o 执行一些操作?返回类型与内部状态和参数无关。方法的语义应该清楚地表明状态或参数是否会改变。如果方法做了更多的事情,它是有意的,那么它就是一种反模式。它更多的是关于干净的编码。
  • 这正是我所追求的——语义不清楚,或者至少在这些情况下是混乱的。

标签: unit-testing mocking anti-patterns


【解决方案1】:

在某种程度上是的。

您所描述的是典型的副作用。副作用使程序难以理解,因为您需要理解的信息不包含在调用堆栈中。您需要更多信息,即在之前(以及以什么顺序)调用了哪些方法。

解决方案是在没有副作用的情况下进行编程。这意味着您不会更改变量、字段或任何东西。相反,您将返回通常会更改的新版本。

这是函数式编程的基本原则。

当然,这种编程方式有其自身的挑战。只考虑 I/O。

【讨论】:

    【解决方案2】:

    如果你这样做,你的代码会更容易测试:

    public interface IMapper
    {
        TargetObject Map(SourceObject source);
    }
    
    public class ClassUnderTest
    {
        private IMapper _mapper;
    
        public ClassUnderTest(IMapper mapper)
        {
            _mapper = mapper;
        }
    
        public int SomeOperation(SourceObject source )
        {
            var target =  _mapper.Map(source, target);
            return target.SomeMappedValue;
        }
    }
    

    您现在可以分别测试 Map 操作和 SomeOperation。问题是你改变了一个对象的状态,这使得很难为测试提供一个存根。返回新对象时,您可以返回目标的测试存根并测试您的调用方方法。

    【讨论】:

    • 是的,绝对的,上面的改变是微不足道的。但有时你不能这么轻易地更改 API。我的问题更多的是人们是否认为这种模式是一种糟糕的设计......
    • 如果你不能测试它,那就是糟糕的设计。这一切都是关于编写可测试的代码。如果它是可测试的,那就更容易理解了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-23
    • 2012-03-11
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 2018-09-22
    相关资源
    最近更新 更多