一个扑克游戏的诞生---扑克牌及相关类代码兼谈异常

一个扑克游戏的诞生---扑克牌及相关类代码兼谈异常

   呵呵,真得很高兴上篇帖子发了以后马上有一个叫ide的朋友对我画的uml图提出了批评,这是我最希望看到的,希望这位ide网友能够继续就这个问题继续指教我一下,呵呵。另外我还是想强调一下,写这篇文章并不是为了给大家做教程,而是希望大家看到我做这个游戏当中从设计到最后完成的设计思路及编程方法,而我做这个游戏也仅仅是为了学习一下.net 而已,所以我希望大家能给我提出批评意见,而不是当作什么大作来读。我也需要学习,也需要提高自己的水平,这也就是尽管我对rose不是很熟悉但我还是敢于自暴其短把我画的uml图贴出来,我不是做范例,而是在展示自己的学习成果,并且我想我所存在的问题可能就是大家初学uml时最可能犯的错误,如果通过对这些问题的讨论能够给我或其他初学uml的人有所帮助,那是最理想不过的事了。我希望大家能指出这篇文章中的错误或不合理的地方,大家共同进步,其他那些和程序设计及编码无关的问题就不在我们讨论的范围之内,所以,请告诉我为什么错,错在那里,正确的应该是怎样,而不是只是简单的说我错了或指摘我某方面的水平,那不是一种好的讨论方式。

   言归正传,继续昨天的问题。通过刚才的类图可以看到有两个前面类设计中没提到的类:CardNotFoundException和CardAlreadyExists类,这两个类都是从System.Exception类继承来的,是自定义异常类。具体代码如下:


CardNotFoudException.cs

using System;


namespace Bigeagle.Games.Cards
{
    /// <summary>
    /// 未找到指定card对象异常
    /// <br>Author: bigeagle</br>
    /// <br>Date: 2002/4/19</br>
    /// <br>History: 2002/4/19</br>
    /// </summary>
    public class CardNotFoundException : System.Exception
    {
        /// <summary>
        /// 牌对象
        /// </summary>
        private Card m_objCard ;

        /// <summary>
        /// 存取牌对象的属性
        /// </summary>
        public Card theCard
        {
            get
            {
                return this.m_objCard ;
            }
            set
            {
                this.m_objCard = value ;
            }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="a_objCard">未找到的牌对象</param>
        public CardNotFoundException(Card a_objCard)
        {
            this.m_objCard = a_objCard ;
        }

        /// <summary>
        /// 重载构造函数
        /// </summary>
        /// <param name="a_objCard">指定的牌对象</param>
        /// <param name="a_strMessage">消息,调用父类构造函数使用</param>
        public CardNotFoundException(Card a_objCard , string a_strMessage):base(a_strMessage)
        {
            this.m_objCard = a_objCard ;
            //base(a_strMessage) ;
        }
    }//end class
}//endnamespace


file : CardAlreadyExistsException.cs

using System;
using Bigeagle.Games.Cards ;

namespace Bigeagle.Games.Cards
{
    /// <summary>
    /// CardAlreadyExistsException 的摘要说明。
    /// </summary>
    public class CardAlreadyExistsException:System.Exception
    {
        /// <summary>
        /// 已存在的牌
        /// </summary>
        private Card m_objCard = new Card() ;

        /// <summary>
        /// 存取牌的属性
        /// </summary>
        public Card theCard
        {
            get
            {
                return this.m_objCard ;
            }
            set
            {
                this.m_objCard = value ;
            }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="a_objCard">牌对象</param>
        public CardAlreadyExistsException(Card a_objCard)
        {
            this.m_objCard = a_objCard ;
        }

        /// <summary>
        /// 重载构造函数
        /// </summary>
        /// <param name="a_objCard">牌对象</param>
        /// <param name="a_strMessage">消息,父类用</param>
        public CardAlreadyExistsException(Card a_objCard , String a_strMessage) : base(a_strMessage)
        {
            this.m_objCard = a_objCard ;
        }
    }//end class
}//end namespace

    这两个类很简单,一个是牌未找到异常,另一个是牌已经存在异常。相信不用我解释大家也能看懂(唯一需要注意的是这两个类构造函数中有个调用父类有参构造函数的用法,如果不太熟悉的话可以看一下相关教程。),那么,为什么要定义这两个异常类呢,为什么不直接抛出一个普通的Exception或者干脆等系统自己来处理呢?说到这里,我想结合上述问题讲一下有关异常的问题,主要原因是在不少朋友的代码里看到有太多的错误使用异常或干脆忽略异常的问题。

    为什么要使用异常以及如何使用异常教科书里都有,我就不再赘述了。现在我要说的是为什么要自定义异常。一个比较成熟的软件项目中,错误处理的代码应该占很大比例,最糟糕的使用异常的方法就是在自己的方法中添加一个空catch子句或者干脆不理他,不处理异常会造成很多问题。既然要处理异常,那就要针对不同的异常来决定不同的处理方法,而不能简单的捕捉一个Exception,这也就是为什么要自定义异常类的原因。举个简单的例子(还是关于扑克牌的),比如说我们现在要生成一副牌然后保存到数据库中,并且要求这副牌中不能有相同的两张牌,如果只是简单的捕捉一个Exception对象,那你在后边的测试纠错中很难直接定位出错的原因,而如果分别捕捉不同的异常,那可以得到丰富的可用于测试纠错的信息。


一个扑克游戏的诞生---扑克牌及相关类代码兼谈异常(中)

file : card.cs

using System;
using System.Diagnostics ;
namespace Bigeagle.Games.Cards
{

    #region 枚举
    /// <summary>
    /// 花色的枚举
    /// </summary>
    public enum CardColors
    {

        /// <summary>
        /// 草花
        /// </summary>
        Club = 0 ,

        /// <summary>
        /// 方块
        /// </summary>
        Diamond  ,

        /// <summary>
        /// 红心
        /// </summary>
        Heart     ,

        /// <summary>
        /// 黑桃
        /// </summary>
        Spade ,

        /// <summary>
        /// 没有花色,对应joker
        /// </summary>
        None
}

    /// <summary>
    /// 牌大小的枚举
    /// </summary>
    public enum CardNumbers
    {
        //Zero = 0 ,
        Two = 2 ,
        Three ,
        Four ,
        Five ,
        Six ,
        Seven ,
        Eight ,
        Nine ,
        Ten ,
        Jack ,
        Queen ,
        King ,
        Ace ,
        ViceJoker ,
        Joker
    }
    #endregion

    /// <summary>
    /// 扑克牌类
    /// <br>author: bigeagle</br>
    /// <br>date: 2002/4/19</br>
    /// <br>History: 2002/4/19</br>
    ///
    /// </summary>
    /// <remarks>继承iComparable接口,用于比较</remarks>
    public class Card : System.IComparable
    {

        #region 成员变量

        /// <summary>
        /// 花色
        /// </summary>
        protected CardColors m_enumColors ;

        /// <summary>
        /// 数字
        /// </summary>
        protected CardNumbers m_enumNumber ;

        #endregion

        #region 属性

        /// <summary>
        /// 存取花色的属性
        /// </summary>
        public CardColors Colors
        {
            get
            {
                return this.m_enumColors ;
            }
            set
            {
                if(value == CardColors.None)
                {
                    throw(new InvalidOperationException
                        ("CardColors.None不能用于Card对象")) ;
                }
//                if(value != CardColors.None)
//                {
//                    this.m_enumColors = value ;
//                }
                this.m_enumColors = value ;
            }
        }

        /// <summary>
        /// 存取大小的属性
        /// </summary>
        public CardNumbers Number
        {
            get
            {
                return this.m_enumNumber ;
            }
            set
            {
                if(value == CardNumbers.Joker
                    || value == CardNumbers.ViceJoker)
                {
                    throw(new InvalidOperationException
                        ("Zero,Joker和ViceJoker不能用于Card对象")) ;
                }
//                if(value != CardNumbers.Joker
//                    && value != CardNumbers.ViceJoker )
//                    this.m_enumNumber = value ;
                this.m_enumNumber = value ;
            }
        }

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        public Card()
        {
            this.m_enumColors = CardColors.Club ;
            this.m_enumNumber = CardNumbers.Ace ;
        }//end method


        /// <summary>
        /// 重载构造函数
        /// </summary>
        /// <param name="a_enumColors">花色</param>
        /// <param name="a_enumNumber">大小</param>
        public Card(CardColors a_enumColors , CardNumbers a_enumNumber)
        {
            if(a_enumColors == CardColors.None
                || a_enumNumber == CardNumbers.Joker
                || a_enumNumber == CardNumbers.ViceJoker)
            {
                throw(new InvalidOperationException
                ("CardColors.None、CardNumbers.Joker和ViceJoker不能用于Card对象")) ;
                
            }
            else
            {
                this.m_enumColors = a_enumColors ;
                this.m_enumNumber = a_enumNumber ;
            }
        }

        #endregion

        #region 改写父类方法

        /// <summary>
        /// 改写ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.m_enumColors.ToString() + " " +  this.m_enumNumber.ToString() ;
        }

        /// <summary>
        /// 重写取得哈希值
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return (int)(System.Math.Pow(100 , (double)this.m_enumColors + 1)
                + (double)this.m_enumNumber) ;
        }

        /// <summary>
        /// 重写equals方法
        /// </summary>
        /// <param name="obj">要判断的对象</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            //断言
            Debug.Assert(obj != null , "要比较的对象不能为空") ;

            return obj.GetHashCode() == this.GetHashCode() ;
        }

        /// <summary>
        /// 改写父接口方法
        /// </summary>
        /// <param name="obj">要比较的对象</param>
        /// <returns>
        /// 小于零 此实例小于 obj。
        /// 零 此实例等于 obj。
        /// 大于零 此实例大于 obj。
        /// </returns>
        public int CompareTo(object obj)
        {
            if(this.GetHashCode() > obj.GetHashCode())
            {
                return 1 ;
            }
            else if(this.GetHashCode() < obj.GetHashCode())
            {
                return -1 ;
            }
            else
            {
                return 0 ;
            }
        }
        
        #endregion


    }//end class
}//end namespace


file: Joker.cs

using System;

namespace Bigeagle.Games.Cards
{
    /// <summary>
    /// Joker
    /// <br>author: bigeagle</br>
    /// <br>date: 2002/4/20</br>
    /// <br>History: 2002/4/20</br>
    /// </summary>
    /// <remarks>继承card类</remarks>
    public sealed class Joker : Bigeagle.Games.Cards.Card
    {
        public Joker()
        {
            this.m_enumColors = CardColors.None ;
            this.m_enumNumber = CardNumbers.Joker ;
        }

        /// <summary>
        /// 改写ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "Joker" ;
        }
    }//end method
}//end namespace


file: ViceJoker.cs

using System;

namespace Bigeagle.Games.Cards
{
    /// <summary>
    /// vice joker
    /// <br>author: bigeagle</br>
    /// <br>date: 2002/4/19</br>
    /// <br>History: 2002/4/19</br>
    /// </summary>
    public sealed class ViceJoker : Bigeagle.Games.Cards.Card
    {
        public ViceJoker()
        {
            this.m_enumColors = CardColors.None ;
            this.m_enumNumber = CardNumbers.ViceJoker ;
        }

        /// <summary>
        /// 改写ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "ViceJoker" ;
        }

    }//end class
}//end namespace

一个扑克游戏的诞生---扑克牌及相关类代码兼谈异常(下)

file: CardCollection.cs

using System;
using System.Diagnostics ;

namespace Bigeagle.Games.Cards
{
    /// <summary>
    /// 牌集合
    /// <br>Author: bigeagle</br>
    /// <br>Date: 2002/4/19</br>
    /// <br>History: 2002/4/19</br>
    /// </summary>
    public class CardCollection : System.Collections.ICollection
    {
        #region 成员变量

        /// <summary>
        /// 牌数组
        /// </summary>
        protected Card[] m_arrCards ;

        /// <summary>
        /// 大小
        /// </summary>
        protected int m_intSize ;

        /// <summary>
        /// 最后一个有效元素的索引
        /// </summary>
        protected int m_intCapacity  ;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        public CardCollection()
        {
            this.m_arrCards = new Card[16] ;
            this.m_intCapacity = -1 ;
            this.m_intSize = 0 ;
        }
        #endregion

        #region 类方法
        /// <summary>
        /// 重新设置容量
        /// </summary>
        /// <param name="capacity">要设置的容量</param>
        private void SetCapacity(int capacity)
        {
            Card[] cards = new Card[capacity];
            if (this.m_intSize > 0)
            {
                if (this.m_intCapacity > 0)
                {
                    Array.Copy(this.m_arrCards , 0 , cards , 0, this.m_intSize) ;
                }
                //                else
                //                {
                //                    Array.Copy(this.m_arrCards , 0 , cards , 0, this.m_arrCards.Length);
                //                    Array.Copy(this.m_arrCards , 0 , cards , this.m_arrCards.Length, this.m_intCapacity);
                //                }
            }
            //this.m_intSize = capacity ;
            this.m_arrCards = cards ;
            //this.m_intCapacity = this.m_intSize -1 ;
        }


        /// <summary>
        /// 取得元素
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        internal Object GetElement(int i)
        {
            if(i < 0 || i >= this.m_intSize)
            {
                throw(new IndexOutOfRangeException()) ;
            }
            return this.m_arrCards[i] ;
        }


        /// <summary>
        /// 添加一个元素
        /// </summary>
        /// <param name="a_objCard"></param>
        public void Add(Card a_objCard)
        {
            foreach(Card c in this.m_arrCards)
            {
                if(c != null && c.Equals(a_objCard))
                {
                    throw(new CardAlreadyExistsException(c , "牌已经存在")) ;
                }
            }

            if (this.m_intCapacity == this.m_arrCards.Length -1)
            {
                int newcapacity = this.m_arrCards.Length + 16 ;
                SetCapacity(newcapacity);
            }
    
            this.m_intCapacity ++ ;
            this.m_arrCards[this.m_intCapacity] = a_objCard;
            this.m_intSize ++ ;
            //this.m_intCapacity ++ ;
            //this.m_intSize ++ ;
    
        }

        /// <summary>
        /// 删除元素
        /// </summary>
        /// <param name="a_objCard">要删除的Card对象</param>
        public void Remove(Card a_objCard)
        {
            Card[] cards = new Card[this.m_arrCards.Length] ;
            int intIndex = -1 ;
            for(int i = 0 ; i < this.m_arrCards.Length ; i ++)
            {
                if(a_objCard == this.m_arrCards[i])
                {
                    intIndex = i ;
                    break ;
                }
            }

            if(intIndex == -1)
            {
                throw(new CardNotFoundException(a_objCard , "集合中未找到指定对象")) ;    
            }
            else
            {
                RemoveAt(intIndex) ;                
            }
        }//end method

        /// <summary>
        /// 删除元素
        /// </summary>
        /// <param name="a_intIndex">要删除元素的索引</param>
        public void RemoveAt(int a_intIndex)
        {
            Card[] cards = new Card[this.m_arrCards.Length] ;

            if(a_intIndex < 0 || a_intIndex > this.m_intSize - 1)
            {
                throw(new IndexOutOfRangeException()) ;    
            }
            else
            {
                
                if(a_intIndex > 0)
                {
                    Array.Copy(this.m_arrCards , 0 , cards , 0 , a_intIndex) ;
                    Array.Copy(this.m_arrCards , a_intIndex + 1 , cards
                        , a_intIndex , this.m_arrCards.Length - a_intIndex -1) ;
                }
                else
                {
                    Array.Copy(this.m_arrCards , 1 , cards , 0 , this.m_arrCards.Length - 1) ;
                }
                this.m_arrCards = cards ;
                this.m_intCapacity -- ;
                this.m_intSize -- ;
            }
        }

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="a_bIsReverse">排序方向,为真则从大到小排列,否则从小到大排列</param>
//        public void Sort(bool a_bIsReverse)
//        {
//            Card temp = new Card() ;
//            for(int i = 0 ; i < this.m_arrCards.Length ; i ++)
//            {
//
//            }
//        }
        #endregion//end 类方法

        #region 重写父接口方法。

        /// <summary>
        /// 拷贝数组
        /// </summary>
        /// <param name="array">数组对象</param>
        /// <param name="index">索引</param>
        public void CopyTo(System.Array array, int index)
        {    
            this.m_arrCards.CopyTo(array , index) ;
        }

        /// <summary>
        /// 取得有效元素数
        /// </summary>
        public int Count
        {
            get
            {
                return this.m_intSize ;
            }
        }

        public bool IsSynchronized
        {
            get
            {
                return false ;
            }
        }

        public object SyncRoot
        {
            get
            {
                return this;
            }
        }

        public System.Collections.IEnumerator GetEnumerator()
        {
            return (new CardEnumerator(this)) ;
        }

        /// <summary>
        /// 重载取得哈希值
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            int result = 0 ;
            for(int i = 0 ; i < this.m_intSize ; i ++)
            {
                result += this.m_arrCards[i].GetHashCode() ;
            }
            return result;
        }

        #endregion

        #region 静态方法


        /// <summary>
        /// 取得一副牌
        /// </summary>
        /// <param name="a_bIncludeJoker"></param>
        /// <returns></returns>
        public static CardCollection GenerateCards(bool a_bIncludeJoker)
        {
            //临时数组
            CardCollection temp = new CardCollection() ;
            
            //产生一个顺序牌集合
            if(a_bIncludeJoker)
            {
                temp.Add(new Joker()) ;
                temp.Add(new ViceJoker()) ;
            }
            Card card ;
            for(int i = 0 ; i < 4 ; i ++)
            {
                for(int j = 14 ; j > 1 ; j --)
                {
                    card = new Card() ;
                    card.Colors = (CardColors)i ;
                    card.Number = (CardNumbers)j ;
                    temp.Add(card) ;
                }
            }

            return temp ;
        }//end method

        /// <summary>
        /// 生成一副随机顺序的牌
        /// </summary>
        /// <param name="a_bIncludeJoker">是否包括大小王</param>
        /// <returns>一副牌,如果包括大小王返回54张牌,否则返回52张</returns>
        public static CardCollection GenerateRandomCards(bool a_bIncludeJoker)
        {
            //结果
            CardCollection result = new CardCollection() ;
            //临时数组
            CardCollection temp = new CardCollection() ;
            //总共产生的牌数
            int intCardCount = a_bIncludeJoker ? 54 : 52 ;

            temp = CardCollection.GenerateCards(a_bIncludeJoker) ;

            //随机排出顺序
            //用时间做种子数,用unchecked关键字防止溢出
            int seed = unchecked((int)DateTime.Now.Ticks) ;
            Random random = new Random(seed) ;
            int index = 0 ;
            while(temp.Count > 0)
            {
                index = random.Next(temp.Count) ;
                result.Add(temp[index]) ;
                temp.RemoveAt(index) ;
            }

            return result ;
        }//end method
        #endregion

        #region 索引器
        /// <summary>
        /// 索引器
        /// </summary>
        public Card this[int Index]
        {
            get
            {
                if(Index < 0 || Index > this.Count)
                {
                    throw(new IndexOutOfRangeException()) ;
                }
                return this.m_arrCards[Index] ;
            }
            set
            {
                if(Index < 0 || Index > this.Count)
                {
                    throw(new IndexOutOfRangeException()) ;
                }
                this.m_arrCards[Index] = value ;
            }
        }
        #endregion

        #region 嵌套类
        /// <summary>
        /// 牌集合迭代
        /// <br>Author: bigeagle</br>
        /// <br>Date: 2002/4/19</br>
        /// <br>History: 2002/4/19</br>
        /// </summary>
        public class CardEnumerator : System.Collections.IEnumerator
        {
            private CardCollection m_objCollection;
            private int m_intIndex;
            private Object m_objCurrentElement;

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="a_objCardCollection"></param>
            internal CardEnumerator(CardCollection a_objCardCollection)
            {
                this.m_objCollection = a_objCardCollection ;
                this.m_intIndex = 0 ;
                this.m_objCurrentElement = this.m_objCollection.m_arrCards ;
                if (this.m_objCollection.m_intSize == 0)
                    this.m_intIndex = -1;
            }

            /// <summary>
            /// 移到下一个元素
            /// </summary>
            /// <returns>如果索引小于0返回假,否则返回真</returns>
            public bool MoveNext()
            {
                if (this.m_intIndex < 0)
                {  
                    this.m_objCurrentElement = this.m_objCollection.m_arrCards ;

                    return false;
                }
                this.m_objCurrentElement = this.m_objCollection.GetElement(this.m_intIndex) ;
                this.m_intIndex ++ ;

                if (this.m_intIndex == this.m_objCollection.m_intSize)
                {
                    this.m_intIndex = -1;
                }

                return true;
            }

            /// <summary>
            /// 重置
            /// </summary>
            public void Reset()
            {
                if (this.m_objCollection.m_intSize == 0)
                {
                    this.m_intIndex = -1;
                }
                else
                {
                    this.m_intIndex = 0;
                }
                this.m_objCurrentElement = this.m_objCollection.m_arrCards ;
            
            }

            /// <summary>
            /// 当前元素
            /// </summary>
            public object Current
            {
                get
                {
                    if (this.m_objCurrentElement == this.m_objCollection.m_arrCards)
                    {
                        if (this.m_intIndex == 0)
                            throw new InvalidOperationException("无效操作");
                        else
                            throw new InvalidOperationException("无效操作");
                    }

                    return this.m_objCurrentElement ;
                }
            }

        }//end class
        #endregion


    }//endclass
}//end namespace
posted on 2005-08-10 14:03  wanna  阅读(169)  评论(0)    收藏  举报