# 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;
}
}
}
```