# QUIZ 8 ###### tags: OOP ## Form1.cs ``` using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using _106_Quiz6; using _106_Quiz7; using System.Collections; namespace _106_Quiz6 { public partial class Form1 : Form { private ArrayList shapeArr = new ArrayList(); // 使用 ArrayList 來儲存產生的形狀物件 private delegate bool CompareFunc(Shape3D a, Shape3D b); //利用委託來傳函式給另一個函式使用 private ShapeType.Material _mType; //紀錄材料類別的欄位, 被兩個事件用到, 故需宣告為類別變數 public Form1() { InitializeComponent(); cboxShape.SelectedIndex = 0; //初始化 comboBox 避免出問題 cBoxMaterial.SelectedIndex = 0; //初始化 comboBox 避免出問題 cboxSortType.SelectedIndex = 0; //初始化 comboBox 避免出問題 } private void btnAddShape_Click(object sender, EventArgs e) { string shape = cboxShape.SelectedItem.ToString(); switch (shape) { case "球": shapeArr.Add(new Ball(Double.Parse(txtPara1.Text), _mType)); // new 出 Ball 物件, 並將其加入 shapeArr中 break; case "立方體": shapeArr.Add(new Cube(Double.Parse(txtPara1.Text), _mType)); break; case "圓柱體": shapeArr.Add(new Cylinder(Double.Parse(txtPara1.Text), Double.Parse(txtPara2.Text), _mType)); break; case "金字塔": shapeArr.Add(new Pyramid(Double.Parse(txtPara1.Text), Double.Parse(txtPara2.Text), _mType)); break; default: break; } txtAmountOfShape.Text = Shape3D.Amount.ToString(); txtBallAmount.Text = Ball.Amount.ToString(); txtCubeAmount.Text = Cube.Amount.ToString(); txtCylinderAmount.Text = Cylinder.Amount.ToString(); txtPyramidAmount.Text = Pyramid.Amount.ToString(); ShowAllShapeInfo(txtMessage); } private void ShowAllShapeInfo(TextBox msg) { string info=""; foreach(Shape3D shape in shapeArr) { info += (shape.ShapeProperty() + "\r\n"); } msg.Text = info; } private void cboxShape_SelectedIndexChanged(object sender, EventArgs e) { string shape = cboxShape.SelectedItem.ToString(); switch (shape) { case "球": lblPara1.Text = "半徑"; lblPara2.Visible= false; txtPara2.Visible = false; break; case "立方體": lblPara1.Text = "邊長"; lblPara2.Visible = false; txtPara2.Visible = false; break; case "圓柱體": lblPara1.Text = "半徑"; lblPara2.Visible = true; lblPara2.Text = "高"; txtPara2.Visible = true; break; case "金字塔": lblPara1.Text = "邊長"; lblPara2.Visible = true; lblPara2.Text = "高"; txtPara2.Visible = true; break; default: break; } } private void cBoxMaterial_SelectedIndexChanged(object sender, EventArgs e) { string material = cBoxMaterial.SelectedItem.ToString(); double density; bool canModified = false; switch (material) { case "鋁": _mType = ShapeType.Material.Al; density = 2.7; break; case "鐵": _mType = ShapeType.Material.Fe; density = 7.87; break; case "鉛": _mType = ShapeType.Material.Pb; density = 11.3; break; default: density = 0; canModified = true; break; } txtDensity.Text = density.ToString(); if (!canModified) txtDensity.Enabled = false; } private void btn_FindHeaviestShape_Click(object sender, EventArgs e) { string info = ""; double maxWeight = 0; foreach (Shape3D shape in shapeArr) { if(shape.Weight() > maxWeight) { maxWeight = shape.Weight(); info = shape.ShapeProperty(); } } txt_ShowHeaviestShape.Text = info; } private bool CompareByShapeTypeAscent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.GeoType > b.GeoType) return true; else return false; } private bool CompareByShapeTypeDescent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.GeoType < b.GeoType) return true; else return false; } private bool CompareByMaterialAscent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.MaterialType > b.MaterialType) return true; else return false; } private bool CompareByMaterialDescent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.MaterialType < b.MaterialType) return true; else return false; } private bool CompareByVolumnAscent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.Volume() > b.Volume()) return true; else return false; } private bool CompareByVolumnDescent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.Volume() < b.Volume()) return true; else return false; } private bool CompareByWeightAscent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.Weight() > b.Weight()) return true; else return false; } private bool CompareByWeightDescent(Shape3D a, Shape3D b) //Ascent =true 時遞增 =false 時遞減 { if (a.Weight() < b.Weight()) return true; else return false; } private void BubbleSort(CompareFunc cmp) //利用委託的方式將 比較函式 傳進 排序函式中, 可以精簡程式碼 { Object temp; // shapeArr 屬於 ArrayList 類別, 每一個元素都是 Object 類別, Object 是所有類別的父類別 for (int pass = 0; pass < shapeArr.Count; pass++) { for (int i = 0; i < shapeArr.Count - 1; i++) { if (cmp((Shape3D)shapeArr[i],(Shape3D)shapeArr[i + 1])) //呼叫不同的 compare function, shapeArr 的元素是 Object 類別, 因此需強制轉型為 Shape3D { temp = shapeArr[i]; shapeArr[i] = shapeArr[i + 1]; shapeArr[i + 1] = temp; } } } } private void btnCofirmSort_Click(object sender, EventArgs e) { switch(cboxSortType.SelectedItem.ToString()) { case "形狀": if (rBtnAscent.Checked) BubbleSort(CompareByShapeTypeAscent); else BubbleSort(CompareByShapeTypeDescent); break; case "材料": if (rBtnAscent.Checked) BubbleSort(CompareByMaterialAscent); else BubbleSort(CompareByMaterialDescent); break; case "體積": if (rBtnAscent.Checked) BubbleSort(CompareByVolumnAscent); else BubbleSort(CompareByVolumnDescent); break; case "重量": if (rBtnAscent.Checked) BubbleSort(CompareByWeightAscent); else BubbleSort(CompareByWeightDescent); break; default: break; } ShowAllShapeInfo(txtSortMessage); } } } ``` ## Shape3D.cs ``` using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _106_Quiz7 { static class ShapeType //靜態類別, 不能被實體化 (new) { public enum Geo //使用 enum 增加程式的可讀性 { UNKNOWN = -1, BALL = 0, CUBE, CYLINDER, PYRAMID }; public enum Material //使用 enum 增加程式的可讀性 { UNKNOWN = -1, Al = 0, Fe, Pb }; } abstract class Shape3D //抽象類別, 不能被實體化 (new) { protected static int _amount; //被繼承的欄位 (資料成員)需宣告為 protected //protected double _density; //被繼承的欄位 (資料成員)需宣告為 protected, _material 與 _density 有相關性 故取消 protected ShapeType.Geo _geoType; protected ShapeType.Material _materialType; //_material 與 _density 有相關性 public Shape3D() { _materialType = ShapeType.Material.UNKNOWN; _amount++; } public Shape3D(ShapeType.Material mType) { _materialType = mType; _amount++; } public static int Amount //要給其他類別取用, 故宣告為 public { get { return _amount; } } public ShapeType.Material MaterialType //要給其他類別取用, 故宣告為 public { get { return _materialType; } } public ShapeType.Geo GeoType //要給其他類別取用, 故宣告為 public { get { return _geoType; } } public abstract double Volume(); //抽象函式, 子類別需進行 override public double Weight() //開放給其他類別使用, 故宣告成 public { return Density() * Volume(); } public double Density() //根據 Material Type 計算 density { double density = 0; switch(_materialType) { case ShapeType.Material.Al: density = 2.7; break; case ShapeType.Material.Fe: density = 7.87; break; case ShapeType.Material.Pb: density = 11.3; break; default: break; } return density; } public abstract string ShapeProperty(); //抽象函式, 子類別需進行 override protected string Property() //只讓子類別呼叫, 故宣告 protected, 抽出子類別重複的程式碼進行重構 { string str=""; str += string.Format("{0,8:F2}", Density()); str += '\t'; str += string.Format("{0,8:F2}", Volume()); str += '\t'; str += string.Format("{0,8:F2}", Weight()); return str; } } } ```