2014年5月4日 星期日

[Code Review] Team 09 - Hw08

整個專案檔連結 https://drive.google.com/file/d/0B9vj2TjBHPutam1SeGxCZ0pvUE0/edit?usp=sharing 換行 Const.cs
namespace HW8___多邊體計算視窗程式3
{
    static class GeoConst
    {
        public static readonly double Pi = 3.14159;  
    }

    static class MetrialConst
    {
        public static readonly double Density_Wood = 0.8;
        public static readonly double Density_Ice = 0.9;
        public static readonly double Density_Al = 2.7;
        public static readonly double Density_Fe = 7.87;
        public static readonly double Density_Pb = 11.3;
        
    }
}
IRollable.cs
namespace HW8___多邊體計算視窗程式3
{
    interface IRollable
    {
        double RollDistance();
    }
}
Shape.cs
namespace HW8___多邊體計算視窗程式3
{
    abstract class Shape
    {//此為抽象類別,不可以實體化,因為形狀不是任何一種形狀
        private static int _count = 0;
        public static int Count { get { return _count; } }

        private double _density = 0;
        public double Density 
        { 
            get { return _density; }
            set { _density = value; }
        }

        static private int _serialNumber; //報名流水號(目前最後的,只增不減)
        public readonly int SerialNumber; //報名流水號(每個物件自己的,new 後不可改)

        //建構子
        public Shape()
        {
            _count++;
            SerialNumber = _serialNumber++;
        }

        //解構子
        ~Shape()
        {
            _count--;
        }
        
        public double Weight()
        {//重量=體積*密度, 不須另外宣告變數存放
            return Bulk() * _density;
        }

        public abstract double Bulk();//體積演算法每種形狀都不同, 留給衍生類實作
    }
}
Ball.cs
namespace HW8___多邊體計算視窗程式3
{
    class Ball : Shape, IRollable
    {
        private static int _count = 0;
        new public static int Count { get { return _count; } }

        //長度參數
        private double _radius = 0;
        
        //建構子
        public Ball(double radius, double density)
        {
            this.Density = density;
            this._radius = radius;
            _count++;
        }

        //解構子
        ~Ball()
        {
            _count--;
        }

        public override double Bulk()
        {
            return (4.0 / 3.0) * GeoConst.Pi * _radius * _radius * _radius;
        }

        public double RollDistance()
        {//prototype at Interface
            return _radius * _radius;
        }
    }
}
Cube.cs
namespace HW8___多邊體計算視窗程式3
{
    class Cube : Shape
    {
        private static int _count = 0;
        new public static int Count { get { return _count; } }

        //長度參數
        private double _side = 0;

        //建構子
        public Cube(double side, double density)
        {
            this.Density = density;
            this._side = side;
            _count++;
        }

        //解構子
        ~Cube()
        {
            _count--;
        }

        public override double Bulk()
        {
            return _side*_side*_side;
        }
    }
}
Cylinder.cs
namespace HW8___多邊體計算視窗程式3
{
    class Cylinder : Shape,IRollable
    {
        private static int _count = 0;
        new public static int Count { get { return _count; } }

        //長度參數
        private double _radius = 0;
        private double _height = 0;

        //建構子
        public Cylinder(double radius, double height, double density)
        {
            this.Density = density;
            this._radius = radius;
            this._height = height;
            _count++;
        }

        //解構子
        ~Cylinder()
        {
            _count--;
        }

        public override double Bulk()
        {
            return GeoConst.Pi * _radius * _radius * _height;
        }

        public double RollDistance()
        {//prototype at Interface
            return _radius * 5;
        }
    }
}
Pyramid.cs
namespace HW8___多邊體計算視窗程式3
{
    class Pyramid : Shape
    {
        private static int _count = 0;
        new public static int Count { get { return _count; } }

        //長度參數
        private double _side = 0;
        private double _height = 0;

        //建構子
        public Pyramid(double side, double height, double density)
        {
            this.Density = density;
            this._side = side;
            this._height = height;
            _count++;
        }

        //解構子
        ~Pyramid()
        {
            _count--;
        }

        public override double Bulk()
        {
            double _dSide = _side/1000;
            double _dHeight = _height/1000;
            double _tempBulk=0;

            for (int i=0; i<1000 ; i++ )
            {//從最底下的那片體積往上加,邊長一直縮小
                double _currentSide = _side - (i * _dSide * 0.5); //0.5 使 side 修正到斜邊中點
                _tempBulk += _currentSide * _currentSide * _dHeight;
            }

            return _tempBulk;
        }
    }
}
Form1.cs
namespace HW8___多邊體計算視窗程式3
{
    public partial class Form1 : Form
    {
        private List ListShape = new List();

        public Form1()
        {
            InitializeComponent();
        }

        private double DensityTable(string material)
        {
            if (material == "木材") return MetrialConst.Density_Wood;
            if (material == "冰") return MetrialConst.Density_Ice;
            if (material == "鋁") return MetrialConst.Density_Al;
            if (material == "鐵") return MetrialConst.Density_Fe;
            if (material == "鉛") return MetrialConst.Density_Pb;

            return -9999;
        }

        private void btnAddNewShape_Click(object sender, EventArgs e)
        {
            ///================ 使用者輸入檢查 開始 ================
            bool _checkPass = false; //標記使用者是否通過防呆檢查
            string _forget = "";     //存放使用者忘記輸入的項目
            int _dummyInt;           //供int.TryParse()檢查用
            double _dummyDouble;     //供double.TryParse()檢查用

            //逐條審查,不可用switch case
            if (null == cbBox_Material.SelectedItem)_forget += " 材質";
            if (null == cbBox_Shape.SelectedItem) _forget += " 形狀";
            if (!int.TryParse(txtBox_AddNewShapeNum.Text, out _dummyInt)) _forget += " 數量";
            if (!double.TryParse(txtBox_ShapeParameter1.Text, out _dummyDouble)) _forget += " 第1個形狀參數";
            if ((cbBox_Shape.SelectedItem.ToString() == "圓柱體") || (cbBox_Shape.SelectedItem.ToString() == "金字塔"))
            {
                if ("" == txtBox_ShapeParameter2.Text) _forget += " 第2個形狀參數";
            }

            //拋出檢查結果. 若無錯誤就Pass
            if ("" != _forget)
                MessageBox.Show("你忘記輸入" + _forget + " !\a");
            else
                _checkPass = true;//無錯誤
            //================ 使用者輸入檢查 結束 ================

            //若是沒有通過防呆檢查,以下這個迴圈會被by pass
            for(int i=0;_checkPass && i小於(轉到32bit整數(文字盒子_AddNewShapeNum.Text));i++)
            {//原本程式碼貼上來網頁會錯誤,後面的程式碼都會亂掉,所以只好這樣寫
                double _localDensity = DensityTable(cbBox_Material.Text);//取得選單所選之密度數值

                switch (cbBox_Shape.SelectedItem.ToString())
                {
                    case "球":
                        {
                            double _tempRadius = Convert.ToDouble(txtBox_ShapeParameter1.Text);
                            ListShape.Add(new Ball(_tempRadius, _localDensity));
                            txtBox_ShapeList1.AppendText("Ball \t"
                                + "半徑=" + Convert.ToString(_tempRadius) + " ");
                        }
                        break;

                    case "正方體":
                        {
                            double _tempSide = Convert.ToDouble(txtBox_ShapeParameter1.Text);
                            ListShape.Add(new Cube(Convert.ToDouble(txtBox_ShapeParameter1.Text), _localDensity));
                            txtBox_ShapeList1.AppendText("Cube \t"
                                + "邊長=" + Convert.ToString(_tempSide) + " ");
                        }
                        break;

                    case "圓柱體":
                        {
                            double _tempRadius = Convert.ToDouble(txtBox_ShapeParameter1.Text);
                            double _tempHeight = Convert.ToDouble(txtBox_ShapeParameter2.Text);
                            ListShape.Add(new Cylinder(_tempRadius, _tempHeight, _localDensity));
                            txtBox_ShapeList1.AppendText("Cylinder \t"
                                + "半徑=" + Convert.ToString(_tempRadius) + " "
                                + "高度=" + Convert.ToString(_tempHeight) + " ");
                        }
                        break;

                    case "金字塔":
                        {
                            double _tempSide = Convert.ToDouble(txtBox_ShapeParameter1.Text);
                            double _tempHeight = Convert.ToDouble(txtBox_ShapeParameter2.Text);
                            ListShape.Add(new Pyramid(_tempSide, _tempHeight, _localDensity));
                            txtBox_ShapeList1.AppendText("Pyramid \t"
                                + "邊長=" + Convert.ToString(_tempSide) + " "
                                + "高度=" + Convert.ToString(_tempHeight) + " ");
                        }
                        break;
                }

                txtBox_ShapeList1.AppendText("編號=" + ListShape.Last().SerialNumber + "\n");
                ReflashNumberOfEachClass();
            }
        }

        private void cbBox_Shape_SelectedIndexChanged(object sender, EventArgs e)
        {//顯示介面控制, 當使用者改變 形狀 時, 動態更動UI

            switch (cbBox_Shape.SelectedItem.ToString())
            {
                case "球":
                    {
                        labelParameter1.Text = "直徑"; txtBox_ShapeParameter1.Visible = true;
                        labelParameter2.Text = ""; txtBox_ShapeParameter2.Visible = false;
                    }
                    break;

                case "正方體":
                    {
                        labelParameter1.Text = "邊長"; txtBox_ShapeParameter1.Visible = true;
                        labelParameter2.Text = ""; txtBox_ShapeParameter2.Visible = false;
                    }
                    break;

                case "圓柱體":
                    {
                        labelParameter1.Text = "直徑"; txtBox_ShapeParameter1.Visible = true;
                        labelParameter2.Text = "高"; txtBox_ShapeParameter2.Visible = true;
                    }
                    break;

                case "金字塔":
                    {
                        labelParameter1.Text = "邊長"; txtBox_ShapeParameter1.Visible = true;
                        labelParameter2.Text = "高"; txtBox_ShapeParameter2.Visible = true;
                    }
                    break;
            }
        }

        private void btnCalcShapeParameter_Click(object sender, EventArgs e)
        {
            if (null == cbBox_SortAlgorithms.SelectedItem)
            {//使用者輸入檢查
                MessageBox.Show("未選擇排序法! 依預設順序列出");
            }
            else
            {
                switch (cbBox_SortAlgorithms.SelectedItem.ToString())
                {
                    case "順序":ListShape.Sort(Sort.BySerialNumber);break;
                    case "形狀":ListShape.Sort(Sort.ByShape);break;
                    case "材質":ListShape.Sort(Sort.ByMetrial);break;
                    case "體積":ListShape.Sort(Sort.ByBulk);break;
                    case "重量":ListShape.Sort(Sort.ByWeight);break;
                }
            }

            txtBox_ShapeList2.Clear();//清除畫面

            for (int i = 0; i < ListShape.Count ; i++)
            {//開始依序列出
                txtBox_ShapeList2.AppendText( ListShape[i].GetType().Name + "\t "
                                            + "密度:" + ListShape[i].Density.ToString("f2") + "\t "
                                            + "體積:" + ListShape[i].Bulk().ToString("f2") + "\t "
                                            + "重量:" + ListShape[i].Weight().ToString("f2") + "\t "
                                            + "編號=" + ListShape[i].SerialNumber
                                            + "\n");
            }
        }

        private void btnCalcRollDistance_Click(object sender, EventArgs e)
        {
            txtBox_ShapeListForRollDistance.Clear();//清除畫面

            for (int i = 0; i < ListShape.Count; i++)//檢查每一個由Shape refenece 管理的物件
            {
                //取得 ListShape[i] 的類別資訊
                bool _isIRollable = ListShape[i] is IRollable;

                if (_isIRollable)
                {//如果是可以滾動的Shape衍生類,就進來
                    IRollable _tempRollable = ListShape[i] as IRollable; //向下轉型
                    
                    txtBox_ShapeListForRollDistance.AppendText(
                        _tempRollable.GetType().Name + "\t " +
                        "滾動距離:" + _tempRollable.RollDistance().ToString("f2") + "\t " + 
                        "\n");
                }
            }//迴圈結束
        }

        private void ReflashNumberOfEachClass()
        {
            label_NumberOfEachClass.Text = "球體=" + Ball.Count + " "
                                            + "正方體=" + Cube.Count + " "
                                            + "圓柱體=" + Cylinder.Count + " "
                                            + "金字塔=" + Pyramid.Count + " "
                                            ;
        }

        private void btnDeleteSomeOneShape_Click(object sender, EventArgs e)
        {
            bool _find = false;

            for (int i = 0; i < ListShape.Count; i++)
            {
                if (ListShape[i].SerialNumber == Convert.ToInt32(txtBox_DeleteSomeOneShapeSerialNum.Text))
                {
                    //強迫回收
                    ListShape[i] = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();

                    //清除空位置
                    ListShape.RemoveAt(i);

                    _find = true;
                    break;
                }
            }

            ReflashNumberOfEachClass();

            if (!_find)
                MessageBox.Show("這個編號的物件不存在!\a");
        }
    }
}

3 則留言:

  1. [第六組]
    第一次看到用在常數那邊的static readonly, google後找到這篇文章.
    http://www.dotblogs.com.tw/yc421206/archive/2011/06/06/27232.aspx
    雖然之前課堂上有人提過const和static作為常數修飾詞的差別,不過後來覺得只是小事就沒去查了... 你們很用心,也提醒了我們這個小細節,感謝!
    namespace的部分一樣還是希望你們注意一下,不要用中文命名.
    Pyramid的體積公式之前有同學提過,建議你改一下,不用再用for迴圈跑XD
    form1.cs的DensityTable,裡面的5個if應該可以改用switch case代替.
    form1.cs:49~50行你可以把.cs檔上傳上來,我會幫你處理.
    form1.cs:排序的部分,自定義比較器是寫在Sort.cs嗎?是的話記得貼上來給大家看一下.
    最後,也要記得提供執行檔讓大家一起測試.

    回覆刪除