假设我们要开发一个多人跳棋游戏。在跳棋游戏中,当一个人走一步棋之后,控制权就轮到下一家,如此轮询,一圈之后控制权又回到自己,然后再继续轮圈下去。我们可以使用数组或列表等数据结构来解决这种转圈圈的问题,但是始终都不够直观。
我设计了 Circle 来对“圈”这种数据结构进行抽象,我们在类似跳棋这样的游戏中可以非常方便地直接使用它。
2. 适用场合:
需要类似“圈”这样的数据结构支持的场合。
3 .设计思想与实现
Circle 也是一个非常简单的数据结构,其类图如下所示:
从类图中显示的
Header
和
Tail
属性,我们看出
Circle
就像一个真正的现实中焊接而成的铁圈一样,是有结合点的,这个结合点就是
Tail
与
Header
交接的地方。
Append 方法用于将一个新的对象附加到 Tail 后面,于是这个新的对象就变成了真正的 Tail 。
Insert 方法用于在指定的地方插入一个新对象,如果当前 Circle 中没有任何对象,则无论其指定的位置是哪里,都将被放置在 Header 的位置。
SetCurrent 方法用于将控制权转交给参数指定的对象。如果指定的对象在 Circle 中不存在,则 SetCurrent 将不执行任何操作。
MoveNext 方法和 MoveBack 方法表示将控制权转移到下一家或上一家。
PeekNext 方法和 PeekBack 方法与 MoveNext 、 MoveBack 含义不一样的地方在于: MoveNext 、 MoveBack 转移了控制权,而 PeekNext 和 PeekBack 没有,它们只是返回下一家或上一家对象。
关于 Circle 的实现要注意以下几点:
(1) Circle 的内部是使用 List 来存放对象的。
(2) Circle 没有进行任何加锁控制,所以它不是线程安全的。我们类似跳棋这样转圈圈的游戏,通常都是以一个有序的顺序来控制游戏的进行的,很少出现多个线程同时修改一个 Circle 的控制权的情况,所以在类似这样的环境中, Circle 就不需要加锁了。
(3)
注意,
InsertAt
方法和
RemoveAt
方法接收的参数
postionIndex
的值允许比内部
List
的最大索引值还大,它们在实现时会对
postionIndex
进行求模运算,将
postionIndex
修正到正确的范围内,在对
List
进行
Insert
和
Remove
操作。
4. 使用时的注意事项
(1) Insert 方法并不会改变 Circle 的当前对象(即 Current 属性的值)。
(2) 当 Circle 中不包含任何元素时, Header 、 Tail 和 Current 属性返回的都是 default(T) 。如果 T 是引用类型,则这个值是 null 。
(3) 当 Circle 中只包含一个元素时, Header 和 Tail 属性将返回同一个对象。
5. 扩展
圈 Circle 暂时没有任何扩展。
在我们后面介绍的 CircleTaskSwitcher (循环任务切换器),它的实现就用到了本节的 Circle 。
注:ESBasic源码可到
http://esbasic.codeplex.com/
下载。