0

这两个片段来自 JDK 源代码:

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false; }

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // increments modCount
    elementData[size++] = e;
    return true;
}

命令-查询分离 (CQS) 指出,每个方法都应该是执行操作的命令或将数据返回给调用者的查询,但不能同时是两者。JDK 源代码中的这两个片段是否违反了 CQS 原则?

4

2 回答 2

1

是的,您引用的代码明显违反了 Bertrand Meyer 定义的命令-查询分离,他于 1988 年在Object Oriented Software Construction中创造了这个术语。CQS 禁止任何具有副作用的例程返回值——甚至是指示成功或失败的状态码。传达此类状态代码的唯一符合 CQS 的方式是让“命令”将状态代码设置在后续“查询”可以检索它的位置。

在他的书的第 4.7 节中,Meyer 区分了可能不返回结果的“过程”和返回结果的“函数”:

“过程”将用于不返回结果的例程,因此我们有两个不相交的例程类别:过程和函数。(在 C 语言的讨论中,术语“函数”本身有时用于表示例程的一般概念,但在这里它总是表示返回结果的例程。)

他继续在第 23.1 节中定义命令-查询分离原则如下:

函数不应产生抽象的副作用。

这是明确的。这不是一个模糊的建议,即您的例程应该“做某事”或“检索一些数据”,但不能两者兼而有之。这是一个明确的要求,例程要么没有副作用,要么没有返回值。

JDK 违反这一原则也就不足为奇了,因为 CQS 并未被广泛接受。迈耶本人在他的书中评论道:

正如您可能已经意识到的那样,这种风格与当今的主流做法非常不同......

他写书的时候我还没有出生,但他的话在三十年后仍然如此。这是否应该归咎于 CQS 不切实际或程序员的主要实践不纯,这是我留给读者的一个问题。

于 2015-06-07T01:37:02.543 回答
-1

add和都是remove改变状态的方法,而不是查询。它们返回有意义的结果。我不认为这违反了 CQS。问题是 CQS 究竟会给这样的操作带来什么价值。

于 2015-06-06T19:11:23.447 回答