iT邦幫忙

1

想請問我的程式碼能在簡潔或是別種寫法

是這樣的最近在學物件導向,老師給我們出作業,大致如圖
https://ithelp.ithome.com.tw/upload/images/20180614/201101326Xp1911RcW.jpg

程式功能是選擇不同交通類型並輸入英里數及燃料容量會計算出他的航程數
這是我的類別裡的程式碼

public abstract class Traffictools :Object
    {
        public int Km { get; set; }
        public int Ml{ get; set; }
        public abstract double Answer();// 
    } 
    public class Car: Traffictools
    {      
        public override double Answer()
        {
            return Km * Ml;
        }
    }
    public class Ship : Traffictools
    {
        public override double Answer()
        {
            return (Km *Ml)*2 ;
        }
    }
    public class Fship : Traffictools
    {
        public override double Answer()
        {
            return (Km * Ml * 2) * 2;
        }
    }

然後這是我表單裡的

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Car mul = new Car();
        Ship mul2 = new Ship();
       
        private void button1_Click(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex == 0)
            {
                try
                {
                    mul.Km = int.Parse(textBox1.Text);
                    mul.Ml = int.Parse(textBox2.Text);
                    label4.Text = "您的航程程數為" + mul.Answer().ToString();
                }
                catch (Exception ex)
                {

                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                try
                {
                   mul2.Km = int.Parse(textBox1.Text);
                   mul2.Ml = int.Parse(textBox2.Text);
                   label4.Text = "您的航程程數為" + mul2.Answer().ToString();
                }
                catch (Exception ex)
                {

                    MessageBox.Show(ex.Message);
                }
                if (checkBox1.Checked)
                {
                   Fship mul3 = new Fship();
                    try
                    {
                        mul3.Km = int.Parse(textBox1.Text);
                        mul3.Ml = int.Parse(textBox2.Text);
                        label4.Text = "您的航程程數為" + mul3.Answer().ToString();
                    }
                    catch (Exception ex)
                    {

                        MessageBox.Show(ex.Message);
                    }
                }               
            }           
        }       
    }

這是我目前所想到的,想請問是否能在精簡一點或是還有別種寫法?

看更多先前的討論...收起先前的討論...
kksugsay iT邦新手 1 級 ‧ 2018-06-14 17:22:14 檢舉
今日回答額度已滿,你無法對此則問題回答。
精簡不精簡可能靠其他高手回答 ..
if (checkBox1.Checked) 這一段是用來判斷帆船的吧?
那應該要放在船(mul2)的上面
不然comboBox1.SelectedIndex=1且checkBox.Checked=true的時候答案會跑兩次
雖然在這個case結果是對的,但就是做了多餘的事情
如果今天船底下的種類除了帆船還有其他三種船,答案不就要跑五次?
Homura iT邦新手 3 級 ‧ 2018-06-15 09:58:43 檢舉
@rainbowrain
我也覺得這樣寫很奇怪
但是他下面回我作業要求....
題目真的這樣要求嗎?XD
乾脆貼出來給大家看看
優悠 iT邦新手 5 級 ‧ 2018-06-15 11:09:33 檢舉
已刪除
tenno081 iT邦新手 5 級 ‧ 2018-06-15 12:35:15 檢舉
痾 ,真的啦,我想那個帆船的意思是要他繼承船的類別,只是我帆船還是給他
繼承父類別這樣
0
海綿寶寶
iT邦超人 1 級 ‧ 2018-06-15 09:33:08
最佳解答

少 7 列,加減參考看看

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        int iKm = int.Parse(textBox1.Text);
        int iMl = int.Parse(textBox2.Text);        
       
        private void button1_Click(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex == 0)
            {
                try
                {
                    Car mul = new Car { Km = iKm, Ml = iMl};
                    label4.Text = "您的航程程數為" + mul.Answer().ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                try
                {
                   Ship mul2 = new Ship { Km = iKm, Ml = iMl};
                   label4.Text = "您的航程程數為" + mul2.Answer().ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                if (checkBox1.Checked)
                {
                    try
                    {
                        Fship mul3 = new Fship { Km = iKm, Ml = iMl};
                        label4.Text = "您的航程程數為" + mul3.Answer().ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }               
            }           
        }       
    }
看更多先前的回應...收起先前的回應...
tenno081 iT邦新手 5 級 ‧ 2018-06-15 12:21:27 檢舉

感謝,可是後來卻顯示欄位初始設定式無法參考非靜態欄位、方法或屬性
form1.textbox1請問這該如何處理?

mio093611 iT邦新手 5 級 ‧ 2018-06-15 14:06:52 檢舉

把int iKm = int.Parse(textBox1.Text);跟int iMl = int.Parse(textBox2.Text);放在點擊行為內就可以了

tenno081 iT邦新手 5 級 ‧ 2018-06-15 15:47:49 檢舉

了解,感謝

謝謝,這樣嗎?

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int iKm = int.Parse(textBox1.Text);
            int iMl = int.Parse(textBox2.Text);        
       
            if (comboBox1.SelectedIndex == 0)
            {
                try
                {
                    Car mul = new Car { Km = iKm, Ml = iMl};
                    label4.Text = "您的航程程數為" + mul.Answer().ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                try
                {
                   Ship mul2 = new Ship { Km = iKm, Ml = iMl};
                   label4.Text = "您的航程程數為" + mul2.Answer().ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                if (checkBox1.Checked)
                {
                    try
                    {
                        Fship mul3 = new Fship { Km = iKm, Ml = iMl};
                        label4.Text = "您的航程程數為" + mul3.Answer().ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }               
            }           
        }       
    }
1
Homura
iT邦新手 3 級 ‧ 2018-06-14 17:47:33

既然是在教物件導向
你可以考慮設計成一個物件
例如Class改成這樣

public class Traffictools
{
    public int Km { get; set; }
    public int Ml { get; set; }

    public double getCaranswer()
    {
        return Km * Ml;
    }
    public double getShipAnswer()
    {
        return (Km * Ml) * 2;
    }
    public double getFshipAnswer()
    {
        return (Km * Ml * 2) * 2;
    }

}

然後Form改成這樣

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Traffictools mul = new Traffictools();
        mul.Km = int.Parse(textBox1.Text);
        mul.Ml = int.Parse(textBox2.Text);

        if (comboBox1.SelectedIndex == 0)
        {
            try
            {                   
                label4.Text = "您的航程程數為" + mul.getCarAnswer().ToString();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
        else
        {
            try
            {
               label4.Text = "您的航程程數為" + mul2.getShipAnswer().ToString();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
            if (checkBox1.Checked)
            {
                try
                {
                    label4.Text = "您的航程程數為" + mul3.getFshipAnswer().ToString();
                }
                catch (Exception ex)
                {

                    MessageBox.Show(ex.Message);
                }
            }               
        }           
    }       
}
看更多先前的回應...收起先前的回應...
tenno081 iT邦新手 5 級 ‧ 2018-06-14 18:07:40 檢舉

對不起,我忘了說,我們今天上課主題是繼承多型,所以才那樣做,真的抱歉

Homura iT邦新手 3 級 ‧ 2018-06-14 19:51:43 檢舉

tenno081是唷
話說你那個帆船,是只有選船時才能勾嗎?
車子就不行?
看你程式是這樣寫...

tenno081 iT邦新手 5 級 ‧ 2018-06-14 20:45:06 檢舉

恩對,我們作業就是要這樣

優悠 iT邦新手 5 級 ‧ 2018-06-15 11:07:43 檢舉

已刪除

Homura iT邦新手 3 級 ‧ 2018-06-15 11:11:07 檢舉

優悠
我怎麼都沒想到
/images/emoticon/emoticon12.gif

Homura iT邦新手 3 級 ‧ 2018-06-15 11:13:42 檢舉

優悠
話說你應該另外貼一篇怎回在這0.0

優悠 iT邦新手 5 級 ‧ 2018-06-15 11:15:19 檢舉

看到就回復了 ,我底下回復好了

1
優悠
iT邦新手 5 級 ‧ 2018-06-15 11:13:30

try catch寫在最外面
不用寫三次,要是一萬個可能性,總不可能寫一萬個...
程式碼抓樓上的,引用下

public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            int iKm = int.Parse(textBox1.Text);
            int iMl = int.Parse(textBox2.Text);

            private void button1_Click(object sender, EventArgs e)
            {
                try
                {
                    if (comboBox1.SelectedIndex == 0)
                    {
                        Car mul = new Car { Km = iKm, Ml = iMl };
                        label4.Text = "您的航程程數為" + mul.Answer().ToString();
                    }
                    else
                    {
                        Ship mul2 = new Ship { Km = iKm, Ml = iMl };
                        label4.Text = "您的航程程數為" + mul2.Answer().ToString();
                        if (checkBox1.Checked)
                        {
                            Fship mul3 = new Fship { Km = iKm, Ml = iMl };
                            label4.Text = "您的航程程數為" + mul3.Answer().ToString();
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
0
kksugsay
iT邦新手 1 級 ‧ 2018-06-15 12:26:31

上面改來改去還是問題一堆,最好要連if esle 都交給factory處理,懶得改了~

public partial class Form1 : Form
{
	public Form1()
	{
		InitializeComponent();
	}

	private void button1_Click(object sender, EventArgs e)
	{
		double answer = "";
		int iKm = int.Parse(textBox1.Text);
		int iMl = int.Parse(textBox2.Text);	
			
		try
		{		
			**if (comboBox1.SelectedIndex == 0)
			{
				Car mul = new Car { Km = iKm, Ml = iMl };
				answer = mul.Answer();
			}
			else
			{
				Ship mul2 = new Ship { Km = iKm, Ml = iMl };
				answer = mul2.Answer();
				if (checkBox1.Checked)
				{
					Fship mul3 = new Fship { Km = iKm, Ml = iMl };
					answer = mul2.Answer();
				}
			}**
			label4.Text = "您的航程程數為" + answer.ToString();				
		}
		catch (Exception ex)
		{
			MessageBox.Show(ex.Message);
		}
	}
}
0
fysh711426
iT邦新手 1 級 ‧ 2018-06-17 15:28:04

大大的題目是多型,多型是指可用相同的操作介面(父類別的抽象方法),操作不同的物件實體(子類別各自實作的方法),降低操作介面對物件的依賴關係。

例如之後新增了新的交通工具飛機,只需在產生子物件的地方新增一個飛機物件,計算航程數的地方不用修改,就能擴充程式功能。

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        var traffictools = null as Traffictools;

        switch(comboBox1.SelectedIndex)
        {
            case 0:
                traffictools = new Car();
                break;
            case 1:
                {
                    if (checkBox1.Checked)
                        traffictools = new Fship();
                    else
                        traffictools = new Ship();
                }
                break;
        }

        traffictools.Km = int.Parse(textBox1.Text);
        traffictools.Ml = int.Parse(textBox2.Text);

        label4.Text = "您的航程程數為" + traffictools.Answer();
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

到這裡已經完成了基本的繼承多型,不過產生物件的地方還是和計算航程數的程式碼綁在一起,就如同上面 kksugsay 大大說的,最好可以將產生物件的地方獨立成 Factory,這麼做的好處是,可以將未來擴充子類別需要變動的地方,和主程式完全隔離開來。

因為產生物件的判斷條件不只是下拉選單,為了方便沒有做得很標準,就新增一個 Create 方法示意。

private Traffictools Create()
{
    switch (comboBox1.SelectedIndex)
    {
        case 0:
            return new Car();
        case 1:
            {
                if (checkBox1.Checked)
                    return new Fship();
                else
                    return new Ship();
            }
        default:
            return null;
    }
}

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        var traffictools = this.Create();
        
        traffictools.Km = int.Parse(textBox1.Text);
        traffictools.Ml = int.Parse(textBox2.Text);

        label4.Text = "您的航程程數為" + traffictools.Answer();
    }
    catch(Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}
看更多先前的回應...收起先前的回應...
tenno081 iT邦新手 5 級 ‧ 2018-06-17 17:52:23 檢舉

太感謝了,這種寫法我還真沒想過,謝謝

tenno081 iT邦新手 5 級 ‧ 2018-06-17 18:39:47 檢舉

您好,有個部分希望能為我講解一下,
就是這種var traffictools = this.Create();
因為我都是用這樣Car mul = new Car();
我想this.Create();應該是把那三個new都涵蓋在裏面吧?
只是這樣我就不太懂traffictools = new Car();這樣的寫法
這種的我還是第一次看到

kksugsay iT邦新手 1 級 ‧ 2018-06-17 20:09:00 檢舉

真的多型要把switch case給處理掉,才叫發揮多型的功能,或是透過反射處理,上面太多改一半等於沒改,雖然偶是懶得寫啦~/images/emoticon/emoticon10.gif

大大理解的沒錯,var traffictools = this.Create();,裡面涵蓋了三個 new,Create 方法會依據 ComboBox 和 CheckBox 的值決定要回傳的子物件,這麼做的用意是,將未來擴充需要變動的地方抽離主程式,不過我沒有做的很標準,有興趣可以 Google 設計模式的工廠方法。

第二個問題 Traffictools traffictools = new Car();
這個寫法是多型的特點,多型是指父類別參考,可在執行期依子類別實體,動態決定要呼叫的函式,達到相同的呼叫,而能產生不同的行為反應,又稱同名異式。

子類別內 override 的用意就在於此,父類別的 Answer 宣告為 abstract 虛擬的,也就是空的方法,而方法的具體內容交給子類別各自實作 (利用 override 覆寫),這樣在利用 traffictools 呼叫 Answer 時,就會根據參考指向的實體,去執行被覆寫的方法。

kksugsay 大大,
小弟想了一下,發現這題好像不能用反射處理,
如果判斷條件只集中在 ComboBox 就可以利用 Value 去產生類別,不過現在還多了一個 CheckBox,難倒小弟了。
/images/emoticon/emoticon70.gif

tenno081 iT邦新手 5 級 ‧ 2018-06-18 10:20:12 檢舉

那再請問,private Traffictools Create(){}這種方法意思是
是將我所做的Traffictools 類別裡的內容全部變成Create方法嗎?

這種寫法的介紹我可以去哪看?抱歉才剛學,很多地方還不是很懂

kksugsay iT邦新手 1 級 ‧ 2018-06-18 10:44:28 檢舉

新手不用太在意這種寫法,只要就自己了解的部份去精簡code就好,重要的是要多寫,等你也寫過數十萬行,理解什麼都不再是問題,不要想著一步到位,過程中還是有很多需要自己去體驗的東西,現在太多想講求速效,卻是寫得太少也想得太少的人,先去磨練後再來談還不遲,寫程式如果沒有寫到讓人痛苦的想死,等於都還是菜鳥,看太多吃不了苦的小鬼頭了,不吃苦就想成為高手,這年頭沒那麼好的事。
f大,程式千變萬化,時常需要換個角度去思考,例如重點不在ComboBox 或是CheckBox,而在於選擇的值,如果用你的想法,那換個元件不就沒完沒了,就點到為止了,因為偶也懶得寫,總之朝這個方向去做,就可以做到心中無劍,手中也無劍,飛~/images/emoticon/emoticon58.gif

這個只是單純的函數,在 C# 裡叫方法,
例如我可以做一個相加的函數,

public int Add(int a, int b)
{
    return a + b;
}

在其他地方呼叫這個 Add 函數,並傳入 a 和 b,此函數就會回傳 a + b 個結果。

var result = Add(2, 3);   //等於 5

回到原問題,呼叫 Create() 函數內部會根據 ComboBox 和 CheckBox 的值,回傳對應的子物件 return new Car(),很棒的是可以利用多型的特性,父類別參考可引用子類別物件,將 Traffictools 當作函數的回傳型態,內部就可以回傳任何子物件。

private Traffictools Create(){}

這裡的 Traffictools 就像上面 Add 函數的 int 一樣,是函數的回傳型態。

tenno081 iT邦新手 5 級 ‧ 2018-06-18 11:31:19 檢舉

太感謝了,因為我覺得我的寫法是以我目前所學及所想到的最精簡的極限
但我知道還可以在更精簡,所以想看看其他寫法

很棒的想法,小弟我也會好奇各種寫法。 /images/emoticon/emoticon34.gif
回 tenno081 大大,程式真的千變萬化,小弟常常太死腦筋了。 /images/emoticon/emoticon56.gif

我要發表回答

立即登入回答