Mail to Keith Dan
keith的天空
海阔凭鱼跃,天高任鸟飞
posts - 32,comments - 196,trackbacks - 2

我发现,不少朋友对于接口这个东西,理论还是比较清楚,但是说不出所以然,对于其应用更加模糊.
借助上面写的一个小程序,讲一下接口问题。
大家可以去下载<<C#象棋游戏>>,互相学习,呵呵。
首先,我们进入今天的主题,接口(interface)用来定义一种程序的协定,这样的概念相信大家都知道,在C#中接口允许多继承,允许包含事件,方法,属性等。
其次,我们再来看,接口,顾名思义,从名字上我们也能看出为一种连接的出入口,那么在我们程序中也是一种出入通道(特别是组件编程)的感觉。

我们来看这个程序,我们先假设这个程序由2个程序员来做,A做棋盘,B做棋子,我们其实也可以不使用接口来做,那么我们A在棋子点击事件中需要写成

private void cib_Click(object sender, EventArgs e)
{
if(sender is ChessItemBing){}
else if(sender is ChessItemJu){}
else if(sender is ChessItemMa){}
else if(sender is ChessItemPao){}

}

当然,在这个程序中类不多,只有7个,大家可以一一判断,此时A必须知道B如何创建类,创建了那些类,但是如果有很多这样的类呢,由或者几个月以后程序有改变呢?会发现,A必须随着B变化而变化,可扩充性非常的差。

那么我们再来看,其中有一个接口,定义了整个棋子的各类属性以及方法。A程序员并不需要知道B程序员创建了那些类,B程序员也不需要知道A程序的代码,AB只需要知道他们的出入口为IChessItem,A所要做的工作只是转换获取该接口

private void cib_Click(object sender, EventArgs e)
        
{

            IChessItem ic 
= (IChessItem)sender;

}

那么B呢,大家可以看到,几个月以后,如果程序有改变,B要做的仅仅是添加类继承此接口,只要接口没改变,那么A的程序可以不做任何的修改。

我们再回过头来看此程序,象棋的棋子有7种,都继承类ChessItemBase,而ChessItemBase他则继承接口,实现这些方法。IChessItem作为模板,也可以说它作为和我们棋盘的通道出入口,棋盘并不知道棋子实际是那一个类,他们所有的超做都来自此接口。

那么可能有朋友会问,我转换为父类也同样能达到效果嘛

private void cib_Click(object sender, EventArgs e)
{
ChessItemBase cib 
= (ChessItemBase )sender;
}

说的不错,在我们这个程序中确实如此,但如果我们程序扩充,添加另一父类ChessItemBase2,ChessItemBase3呢,你会发现,A还是要重写判断为ChessItemBase,ChessItemBase2,ChessItemBase3,的代码,所以这都不利于我们程序的扩充。

接口比较抽象,看到许多书上,以及网上很多文章对接口写的很书面化,很多人看的云里雾里,所以上了这边文章.
以上是我对接口的一个个人理解,可能语言不太专业,可能大家对此持有其他不同的意见,欢迎发表.

posted @ 2006-12-06 17:43 KeithDan 阅读(1935) 评论(8) 编辑
这个程序是为我的学生做的一个象棋游戏,里面涉及大家有兴趣的朋友可以下载来看看

其中绘制了一个虚拟网格,其中网格分布为9X10分布,和正规象棋布局一样,即GridX,GridY作为该网格的X,Y坐标,所有坐标点均采用此虚拟网格进行转换

其中定义了一个棋子接口,所有棋盘和棋子之间的交互均来自此接口
public interface IChessItem
    
{
        
/// <summary>
        
/// 为蓝方还是红方
        
/// </summary>

        Enums.ChessType type{get;set;}
        
/// <summary>
        
/// 是否被按下
        
/// </summary>

        bool IsChecked{get;set;}
        
/// <summary>
        
/// 移动的步长X
        
/// </summary>

        int StepX{get;}
        
/// <summary>
        
/// 移动的步长Y
        
/// </summary>

        int StepY{get;}
        
/// <summary>
        
/// 在棋盘网格中的X坐标
        
/// </summary>

        int GridX{get;set;}
        
/// <summary>
        
/// 在棋盘网格中的Y坐标
        
/// </summary>

        int GridY{get;set;}
        
/// <summary>
        
/// 移动棋子
        
/// </summary>
        
/// <param name="ChessX">将要移动的网格X坐标</param>
        
/// <param name="ChessY">将要移动的网格Y坐标</param>
        
/// <returns>是否成功移动</returns>

        bool MoveItem(int ChessX,int ChessY);
        
/// <summary>
        
/// 初始化棋子
        
/// </summary>

        void InitItem();
        
/// <summary>
        
/// 移除棋子,作为被其他棋子吃掉
        
/// </summary>

        void Remove();
    }

其中有两个比较重要的事件
private void cib_Click(object sender, EventArgs e)
此事件为棋子被点机事件,由它来响应棋子的选中以及吃别的棋子,名字没改,呵呵,不好意思

private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
此事件做为棋子实现移动

所有棋子移动均来源于IChessItem接口中的
bool MoveItem(int ChessX,int ChessY);

由于是给我学生看,此程序比较简单,所以流程也比较简单.学习C#的朋友可以来看一下,呵呵
其中算法麻烦一点的是炮的翻山,马的蹩脚,象的蹩脚

所有棋子继承ChessItemBase,其中一些棋子重写函数public virtual bool LimitPoint(int ChessX,int ChessY)以实现自己的特殊限制移动,比如炮,马,象,兵等

Demo Soure
posted @ 2006-12-06 00:08 KeithDan 阅读(4528) 评论(21) 编辑