可观察状态

2006年1月5日

当人们说一个方法不会改变对象的可观察状态时,他们指的是什么?

将方法分为改变状态的方法和不改变状态的方法非常有用。不改变状态的方法(我称之为查询)可以在任何上下文中使用,而无需担心它们与其他方法的排序方式。

这里的关键不是它们不改变任何状态,而是它们不改变 *可观察* 状态。对象的可观察状态是指可以通过其查询方法检测到的状态 - 让我用几个简单的例子来说明。

最简单的例子是缓存。想象一下这样的范围类。

# ruby
class MyRange
  attr_reader :start, :finish
  def initialize start, finish
    @start, @finish = start, finish
    @lengthCache = nil
  end
  def length
    @lengthCache = (@finish - @start) unless @lengthCache
    return @lengthCache
  end
end

这里我们有一个 lengthCache 变量,它在第一次访问时使用 延迟初始化 填充。将值放入 lengthCache 显然会改变对象的真实状态。它不会改变可观察状态,因为你无法从外部判断对象的 state 发生了变化。

从外部无法判断是指,从另一个对象调用 MyRange 上的任何方法的结果,无论 lengthCache 值是否已填充,都将相同。

通常,你可以通过确保 MyRange 上的任何方法都使用 length 方法来获取范围,而不是直接使用字段来获得这种效果。缓存是状态更改永远不应该被观察到的一个明显案例。任何延迟初始化也不应该改变可观察状态也是真的。