购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

建议24:迭代器应该是只读的

如果注意观察会发现,FCL中的迭代器只有GetEnumerator方法,没有SetEnumerator方法。所有的集合类也没有一个可写的迭代器属性。有的时候,我们可能会疑惑,为什么不公开这样一个接口,以便满足可能需要的多出来的迭代需求呢?原因有二。

其一:这违背了设计模式中的开闭原则。被设置到集合中的迭代器可能会直接导致集合的行为发生异常或变动。一旦确实需要新的迭代需求,完全可以创建一个新的迭代器来满足需求,而不是为集合设置该迭代器,因为这样做会直接导致使用到该集合对象的其他迭代场景发生不可知的行为。

其二:现在,我们有了LINQ。使用LINQ可以不用创建任何新的类型就能满足任何的迭代需求(见建议30)。

现在通过代码来看一下,若迭代器不是只读的,会存在什么样的危害。假设存在一个公共集合对象,有两个业务类需要对这个集合对象进行操作。其中,业务类A只负责将元素迭代出来显示到UI上:


IMyEnumerable list=new MyList();

IMyEnumerator enumerator=list.GetEnumerator();

while(enumerator.MoveNext())

{

int current=enumerator.Current;

Console.WriteLine(current.ToString());

}


业务类B出于自己的某种需求,需要实现一个新的针对集合对象的迭代器,于是它这样操作:


MyEnumerator2 enumerator2=new MyEnumerator2(list as MyList);

(list as MyList).SetEnumerator(enumerator2);

while(enumerator2.MoveNext())

{

int current=enumerator2.Current;

Console.WriteLine(current.ToString());

}


问题的关键是,现在再回到业务类A中执行一次迭代显式,结果将会是B所设置的迭代器完成输出。这相当于B在没有通知A的情况下对A的行为进行了干扰,这种情况是应该避免的。

事实上,上面的代码即使没有下面这行代码也会运行得很好:


(list as MyList).SetEnumerator(enumerator2);


所以,迭代器模式的原则是:

不要为迭代器设置可写属性。 g9kgXsxkQM4h2LVH/NrIWh1eZYX7dW+RRNh9mnPcVKYj5gxtSDzTj58t619wjBZ9

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开