https://drive.google.com/file/d/0B9vj2TjBHPutWVBablNsVU5NNTJ0MTdmd0lrQjRGQ0FlbU00/edit?usp=sharing
Form1 開頭部分(一開始忘記貼,4/14 am03:47 補上)
private List<Shape> ListShape = new List<Shape>();
public Form1()
{
InitializeComponent();
}
private double DensityTable(string p_Material)
{
if (p_Material == "鐵") return 13;
if (p_Material == "冰") return 1;
if (p_Material == "木材") return 0.8;
return -9999;
}
加入新Shape按鈕private void btnAddNewShape_Click(object sender, EventArgs e)
{
///================ 使用者輸入檢查 開始 ================
bool CheckPass = false; //標記使用者是否通過防呆檢查
string Forget = ""; //存放使用者忘記輸入的項目
int DummyInt; //供int.TryParse()檢查用
double DummyDouble; //供double.TryParse()檢查用
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 == "圓柱體") || (cbBox_Shape.SelectedItem == "金字塔"))
{
if ("" == txtBox_ShapeParameter2.Text) Forget += " 第2個形狀參數";
}
//拋出檢查結果. 若無錯誤就Pass
if ("" != Forget)
MessageBox.Show("你忘記輸入" + Forget + " !\a");
else
CheckPass = true;
///================ 使用者輸入檢查 結束 ================
//若是沒有通過防呆檢查,以下這個迴圈會被by pass
for(int i=0; CheckPass && i<Convert.ToInt16(txtBox_AddNewShapeNum.Text);i++)
{
if (cbBox_Shape.SelectedItem == "球")
{
double tempRadius = Convert.ToDouble(txtBox_ShapeParameter1.Text);
ListShape.Add(new Ball(tempRadius, DensityTable(cbBox_Material.Text)));
//顯示在txtBox_ShapeList
txtBox_ShapeList1.AppendText("Ball "
+ "半徑="+ Convert.ToString(tempRadius) +" "
+ "\n");
}
if (cbBox_Shape.SelectedItem == "正方體")
{
double tempSide = Convert.ToDouble(txtBox_ShapeParameter1.Text);
ListShape.Add(new Cube(Convert.ToDouble(txtBox_ShapeParameter1.Text), DensityTable(cbBox_Material.Text)));
//顯示在txtBox_ShapeList
txtBox_ShapeList1.AppendText("Cube "
+ "邊長=" + Convert.ToString(tempSide) + " "
+ "\n");
}
if (cbBox_Shape.SelectedItem == "圓柱體")
{
double tempRadius = Convert.ToDouble(txtBox_ShapeParameter1.Text);
double tempHeight = Convert.ToDouble(txtBox_ShapeParameter2.Text);
ListShape.Add(new Cylinder(tempRadius, tempHeight, DensityTable(cbBox_Material.Text)));
//顯示在txtBox_ShapeList
txtBox_ShapeList1.AppendText("Cylinder "
+ "半徑=" + Convert.ToString(tempRadius) + " "
+ "高度=" + Convert.ToString(tempHeight) + " "
+ "\n");
}
if (cbBox_Shape.SelectedItem == "金字塔")
{
double tempSide = Convert.ToDouble(txtBox_ShapeParameter1.Text);
double tempHeight = Convert.ToDouble(txtBox_ShapeParameter2.Text);
ListShape.Add(new Pyramid(tempSide, tempHeight, DensityTable(cbBox_Material.Text)));
//顯示在txtBox_ShapeList
txtBox_ShapeList1.AppendText("Pyramid"
+ "邊長=" + Convert.ToString(tempSide) + " "
+ "高度=" + Convert.ToString(tempHeight) + " "
+ "\n");
}
}
}
========================================================形狀選單更動
private void cbBox_Shape_SelectedIndexChanged(object sender, EventArgs e)
{//顯示介面控制, 當使用者改變 形狀 時, 動態更動UI
if (cbBox_Shape.SelectedItem == "球")
{
labelParameter1.Text = "直徑"; txtBox_ShapeParameter1.Visible = true;
labelParameter2.Text = ""; txtBox_ShapeParameter2.Visible = false;
}
if (cbBox_Shape.SelectedItem == "正方體")
{
labelParameter1.Text = "邊長"; txtBox_ShapeParameter1.Visible = true;
labelParameter2.Text = ""; txtBox_ShapeParameter2.Visible = false;
}
if (cbBox_Shape.SelectedItem == "圓柱體")
{
labelParameter1.Text = "直徑"; txtBox_ShapeParameter1.Visible = true;
labelParameter2.Text = "高"; txtBox_ShapeParameter2.Visible = true;
}
if (cbBox_Shape.SelectedItem == "金字塔")
{
labelParameter1.Text = "邊長"; txtBox_ShapeParameter1.Visible = true;
labelParameter2.Text = "高"; txtBox_ShapeParameter2.Visible = true;
}
}
=========================================================計算按鈕
private void btnCalcShapeParameter_Click(object sender, EventArgs e)
{
txtBox_ShapeList2.Clear();
for (int i = 0; i < ListShape.Count ; i++)
{
txtBox_ShapeList2.AppendText( ListShape[i].getObjName() + " "
+ "密度:" + ListShape[i].Density + " "
+ "體積:" + ListShape[i].getBulk() + " "
+ "重量:" + ListShape[i].getWeight() + " "
+ "\n");
}
}
=========================================================Shape類別(其他類別的基礎類別)
abstract class Shape
{//此為抽象類別,不可以實體化,因為形狀不是任何一種形狀
private static int count = 0;
protected static double Pi = 3.14159;
protected double density=0;
public Shape Next = null;
abstract public string getObjName();//每個形狀名字不一樣, 留給衍生類實作
public Shape()
{
count++;
}
~Shape()
{
count--;
}
public static int Count
{//從物件外只能get, 不能set
get { return count; }
}
public double Density
{//這是屬性
get {return density; }
}
public double getWeight()
{//重量=體積*密度, 不須另外宣告變數存放
return getBulk() * density;
}
public abstract double getBulk();//體積演算法每種形狀都不同, 留給衍生類實作
}
=========================================================Ball類別(繼承自Shape)
class Ball : Shape
{
public double radius=0;
private static int count = 0;
public override string getObjName() { return "Ball"; }
public Ball(double p_radius, double p_density)
{
this.density = p_density;
this.radius = p_radius;
count++;
}
~Ball()
{
count--;
}
new public static int Count
{//從物件外只能get, 不能set
get { return count; }
}
public override double getBulk()
{
return (4.0 / 3.0) * Pi * radius * radius * radius;
}
}
=========================================================
Cube類別(繼承自Shape)
Cube類別(繼承自Shape)
class Cube : Shape
{
public double side;
private static int count = 0;
public override string getObjName() { return "Cube"; }
public Cube(double p_side, double p_density)
{
this.density = p_density;
this.side = p_side;
count++;
}
~Cube()
{
count--;
}
new public static int Count
{//從物件外只能get, 不能set
get { return count; }
}
public override double getBulk()
{
return side*side*side;
}
}
Cylinder類別(繼承自Shape)
class Cylinder : Shape
{
public double radius;
public double height;
private static int count = 0;
public override string getObjName() { return "Cylinder"; }
public Cylinder(double p_radius, double p_height, double p_density)
{
this.density = p_density;
this.radius = p_radius;
this.height = p_height;
count++;
}
~Cylinder()
{
count--;
}
new public static int Count
{//從物件外只能get, 不能set
get { return count; }
}
public override double getBulk()
{
return Pi * radius * radius * height;
}
}
=========================================================Pyramid類別(繼承自Shape)
class Pyramid : Shape
{
public double side;
public double height;
private static int count = 0;
public override string getObjName() { return "Pyramid"; }
public Pyramid(double p_side, double p_height, double p_density)
{
this.density = p_density;
this.side = p_side;
this.height = p_height;
count++;
}
~Pyramid()
{
count--;
}
new public static int Count
{//從物件外只能get, 不能set
get { return count; }
}
public override double getBulk()
{
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;
}
}
林高遠:這是我寫的,使用者錯誤檢查那邊,我用的是類似<大話設計模式>中提的 範本方法模式(Template Method),只是沒跨類別實作
回覆刪除請大家快來批評我,謝謝
第8組
回覆刪除錯誤檢查判斷的好仔細(Y)
但可以請問 Class Shape 內的 public Shape Next = null;
這行的Next成員的功用嗎 ?
我本來要自幹Linklist,但是搞不定傳址,所以這是Linklist難產的闌尾,可割可棄
刪除[第六組]
回覆刪除檢查輸入錯誤的部分真的不錯!
第一塊程式碼:28行for迴圈內的檢查,用switch或者if...else應該會比較有效率. 因為當使用者選擇"球"時,現在的寫法就算跑完了球的處理部分,還是會再往下繼續判斷每個if,有點浪費時間(雖然if判斷很快...).
第二塊程式碼:選單隱藏或顯現的變動,這樣寫也可以. 只是一樣要注意一樣全部只用if和使用switch或if...else的差別.
謝謝你,你說的缺點我有注意到
刪除因為我不是用數字做選項判斷,我是用字串,所以不能用switch case;我認為在x86上用字串判斷維持程式可讀性,比省下幾個 if else 判斷時間來的更好
1. 原來這才是正宗版本,難怪上一個版本那麼驚悚...。
回覆刪除2. 整個架構包含註解都相當完整,看起來真的是賞心悅目,我認為把防呆放在一起處理也是一個好設計。
3. 注意一下防呆部分,不是真的轉得過去就OK了,這個程式碼會讓參數為負值的照樣通過,需要再一點點的判斷。
4. 看到數值積分出來都囧了,你要不要google一下角錐體積怎麼算。
1. 我想版本或許有高低之分,但無所謂正宗或不正宗。因為,就算寫得再差,那還是我們組員的作品
刪除3. 沒錯, 數量不能是負的, 謝謝提醒
4. 這段程式碼在火車上寫的, 沒網路, 所以就只好硬幹了...
作者已經移除這則留言。
回覆刪除(第九組)
回覆刪除1.形狀設定為球或是圓柱體時,輸入欄位的名稱應該是半徑,而不是直徑
2.輸入數量的地方有點多餘,因為計算的參數都一樣,同樣的東西不需要計算這麼多遍
嗯嗯謝謝,不講我都沒注意到
刪除衍生類別中的count為何不用加new(隱藏繼承)??跟你所用的虛擬類別有關嗎?
回覆刪除因為private
刪除