完整的程序代码可以从http://www2.cnblogs.com/Files/zhenyulu/HRD.rar下载
九、 代码设计
在看完了解题过程后,下面来看一看具体的代码设计方案:
我们首先从Core开始,在Core.dll里面定义了系统所需的最基本的数据类型以及相关的接口。其中枚举ChessmanType与MoveMethod分别定义了棋子的类型以及棋子移动的方法。
{
Blank = 0,
Solider = 1,
VChessman = 2,
HChessman = 3,
General = 99
}
public enum MoveMethod
{
Up,
Down,
Left,
Right,
Up2,
Down2,
Left2,
Right2,
Turning,
Nothingness //没有任何移动
}
ChessStep定义了棋局中的"一步"棋。包括当前棋盘布局的整数表示、移动了哪一个棋子以及如何移动。当华容道自动解题程序完成后,将返回一个ChessStep[]数组,记录每一步的走法。我们可以通过实现IResultHandler接口的"HandleResult (ChessStep[] steps)"方法来达到这一目的。IResultHandler接口将在后面加以介绍。
{
public short chessmanNum;
public MoveMethod moveMethod;
public int layout;
}
Position与BlankPosition是两个结构"structure",用来记录棋子的位置以及某一棋盘上空格的位置。BlankPosition中有一IsBlank(int x, int y)方法,用来判断坐标为(x,y)的点是否是空格。
{
public int x;
public int y;
public Position(int x, int y)
{
this.x = x;
this.y = y;
}
}
public struct BlankPosition
{
public Position Pos1;
public Position Pos2;
public BlankPosition(Position pos1, Position pos2)
{
this.Pos1 = pos1;
this.Pos2 = pos2;
}
public bool IsBlank(int x, int y)
{
if( x == Pos1.x && y == Pos1.y)
return true;
if( x == Pos2.x && y == Pos2.y)
return true;
return false;
}
}
之所以选择使用结构而不是类是因为struct是值类型的,而class是引用类型。在本程序中,struct要比class更有效率。关于struct与class的区别在这里就不再详细讨论了。我们看下面一段程序:
Position P2;
P2 = P1;
P2经过赋值后,P2.x与P2.y都与P1相同,并且这种赋值不是"引用"赋值,修改P2中x、y的值并不会影响P1中x、y的值。
HRD.Core命名空间下除了这些基本类型的定义外,还定义了一系列接口,主要是用来达到解耦目的。在上篇文章中,我们看到了TreeLinkedList、CircularLinkedList以及AVLTree之间如何协作工作,但在实际代码设计中,这将带来严重的耦合问题。组件与组件之间联系过于紧密,造成无法有效的剥离。为此,程序在设计时引入了"中介者"模式,设计了一个Mediator,所有组件仅与Mediator打交道,这样耦合便被"松动"了。
Mediator的定义如下:
{
private IAVLTree _avlTree;
private ICircularList _circleList;
private ITreeList _treeList;
private IResultHandler _resultHandler;
…………
}
其中IAVLTree、ICircularList、ITreeList便是参与运算的三种数据结构。其具体定义可以参考具体的程序源代码。(可以参考http://www2.cnblogs.com/zhenyulu/archive/2005/02/03/101426.html里面的代码,但不是最终版本,可能会与本文有所出入)。
这里还有一个接口定义,就是IResultHandler接口。刚才已经提到过。我们可以将一个实现了该接口的对象传递给Mediator对象,这样,当系统运算完成后便会调用IResultHandler中的特定方法,将结果回传。
{
void HandleResult(ChessStep[] steps);
void HandleInfo(int currentStep);
}
IResultHandler定义了两个方法HandleResult与HandleInfo。HandleResult用来处理程序产生的结果,结果以ChessStep数组的形式传入。HandleInfo可以被用来处理程序运算过程中的一些中间信息。这里我只提供了一个信息,那就是当前搜索层次是什么。它通过currentStep参数传入。如果需要,用户可以重新定义该接口以获取更多的信息(例如搜索了多少个节点等)。IResultHandler接口的具体使用方法可以参考源代码中WinHRD或ConsoleHRD中的实现。
HRD.Core命名空间下还定义了Layout以及Chessman,此外还有一个CallBackDelegate的定义,这些将在后续的文章中再加以介绍。