Re: [問題] 變數宣告在if結構裡

看板C_Sharp (C#)作者 (笨嘎嘎)時間10年前 (2014/05/19 14:14), 10年前編輯推噓7(7049)
留言56則, 7人參與, 最新討論串4/5 (看更多)
你這樣寫會讓其他人亂用繼承關係。 原PO的解答的確是要用多型,Abb大寫的沒錯。 但是「如何寫」是一回事, 你有用到DesignPattern的概念,寫出來的東西卻打了自己一巴掌。 ====文字檔==== 文字檔Father.txt Father My name is Darth Vader. I am your Father! 文字檔Son.txt Son My name is Luke Skywalker. No~~~~~~~~~! ====程式碼==== 程式碼Family.cs abstract public class Family { public string StrA { get; set; } public string StrB { get; set; } public Family(StreamReader reader) { this.StrA = reader.ReadLine(); this.StrB = reader.ReadLine(); } public abstract void ShowStrA(); public abstract void ShowStrB(); } 程式碼Father.cs public class Father : Family { public Father(StreamReader reader) : base(reader) { } public override void ShowStrA() { Console.WriteLine(this.StrA); } public override void ShowStrB() { Console.WriteLine(this.StrB); } } 程式碼Son.cs public class Son : Family { public Son(StreamReader reader) : base(reader) { } public override void ShowStrA() { Console.WriteLine(this.StrA); } public override void ShowStrB() { Console.WriteLine(this.StrB); } } 程式碼FamilyFactory.cs public class FamilyFactory { public static Family CreateFamily(string familyMember, StreamReader reader) { if (familyMember == "Father") { return new Father(reader); } else if (familyMember == "Son") { return new Son(reader); } else { return null; } } } 客戶端調用 StreamReader reader1 = new StreamReader("Father.txt"); StreamReader reader2 = new StreamReader("Son.txt"); string familyMember1 = reader1.ReadLine(); string familyMember2 = reader2.ReadLine(); Family family1 = FamilyFactory.CreateFamily(familyMember1, reader1); Family family2 = FamilyFactory.CreateFamily(familyMember2, reader2); family1.ShowStrA(); family2.ShowStrA(); family1.ShowStrB(); family2.ShowStrB(); 結果 My name is Darth Vader. My name is Luke Skywalker. I am your Father! No~~~~~~~~~! Father類別或Son類別是不同的, 只有新手或不熟悉物件導向的人才會直接用Son來繼承Faher, 這兩個類別都應該抽像於Family類別, 這樣子寫才比較好維護也有彈性。 Abb大說的多型是這樣, 只不過我偷懶把strA跟strB的readline寫在建構式。 ※ 引述《adrianc (123)》之銘言: : 看完後整整十分鐘心神不寧無法繼續工作,決定趁吃飯前回一下。 : 由原PO回文中已知兩個類別是繼承關係。 : 依照原文推文中的Abb大建議,實作程式碼。 : // 以下程式碼依原程式內容 : // 預期檔案第一行可能讀到 "father" or "son" 之外的內容,且不須處理 : // 變數命名使用原程式命名方式 : private void button1_Click(object sender, EventArgs e) : { : System.IO.StreamReader file = new System.IO.StreamReader("file.txt"); : string str = file.ReadLine(); : ClassFather xxx = null; : if (str == "father) : { : xxx = new ClassFather(); : } : else if (str == "son") : { : xxx = new ClassSon(); : } : if (xxx != null) : { : xxx.strA = file.ReadLine(); : xxx.strB = file.ReadLine(); : } : } : --------------------------------------------------------------- : ClassFather xxx = null; : . : . : . : xxx = new ClassSon(); : } : 這段視你的需求可以考慮用 : ClassFather xxx = FatherSonClassFactory.Create(str); : 來替換掉 : 然後 C# (物件導向) 的 method 主要功能應該不是用來排版.. : ※ 引述《LetsGoToEat (一起去吃東西吧)》之銘言: : : 感謝幫忙,我試著改成這樣 : : private void button1_Click(object sender, EventArgs e) : : { : : System.IO.StreamReader file = new System.IO.StreamReader("file.txt"); : : string str = file.ReadLine(); : : if (str == "father") : : { : : ClassFather xxx = new ClassFather(); : : IamFunction(file, xxx); : : } : : else if (str == "son") : : { : : ClassSon xxx = new ClassSon(); : : IamFunction(file, xxx); : : } : : } : : private void IamFunction(System.IO.StreamReader file, ClassFather xxx) : : { : : xxx.strA = file.ReadLine(); : : xxx.strB = file.ReadLine(); : : } : : 似乎是可以了@@ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.249.117.38 ※ 文章網址: http://www.ptt.cc/bbs/C_Sharp/M.1400480064.A.F24.html ※ 編輯: StupidGaGa (60.249.117.38), 05/19/2014 14:17:48

05/19 14:48, , 1F
你要不要看一下原po回文的 IamFunction 方法簽名
05/19 14:48, 1F

05/19 14:49, , 2F
再想想為什麼這樣寫? 這樣看不懂我也不解釋了
05/19 14:49, 2F

05/19 14:50, , 3F
另外 這邊的抽象物件 (Father也好 Family也好)
05/19 14:50, 3F

05/19 14:52, , 4F
認識 StreamReader 本身就是..嗯..所謂的"新手"寫法了..
05/19 14:52, 4F
我已經說過,我偷懶寫在建構式裡面, streamReader要拔掉沒差,重點是觀念, 類別本來不應該繼承類別, 類別是要繼承於抽像類別或介面。 繼承的觀念是is,難道你會說son is father? 為什麼我要father跟son抽像,然後都繼承family? 因為實作跟維護上我看過太多人都亂繼承, 如同你寫的範例,son繼承於father,這是不對的寫法。 如果你有去了解DesignePattern, 你會了解為什麼son跟father要繼承於family。 ※ 編輯: StupidGaGa (60.249.117.38), 05/19/2014 15:01:20

05/19 14:56, , 5F
基本上 這個案例根本牽扯不上 DesignPattern 所以
05/19 14:56, 5F

05/19 14:57, , 6F
我還特別在原範例中跳過 Factory 以免模糊焦點
05/19 14:57, 6F
就算不管DesignPattern, 我還是那句話, 類別不該繼承於類別, 類別應該繼承於抽像類別或介面。 ※ 編輯: StupidGaGa (60.249.117.38), 05/19/2014 15:05:24

05/19 15:23, , 7F
我還真閒... 1. 不知道你是不是看出原po"已經"繼承類別了
05/19 15:23, 7F

05/19 15:24, , 8F
2. 如果用偷懶解釋的話 那所有的 dirty code 都是合理的
05/19 15:24, 8F

05/19 15:24, , 9F
我們也不需要再往下討論了
05/19 15:24, 9F

05/19 15:25, , 10F
3. 我不知道 "son is father" 成不成立 至少已知資訊中
05/19 15:25, 10F

05/19 15:26, , 11F
沒有超能力是看不出來的 我只能從物件行為判斷
05/19 15:26, 11F

05/19 15:32, , 12F
4. 物件導向設計原則中 只有依賴倒轉原則
05/19 15:32, 12F

05/19 15:33, , 13F
但沒有一條告訴你 "類別不該繼續於類別"
05/19 15:33, 13F

05/19 15:33, , 14F
需要從framework找些 "類別繼承類別的"例子給您嗎?
05/19 15:33, 14F

05/19 15:36, , 15F
5. again "我寫的範例"中 沒有包括 son 繼承 father
05/19 15:36, 15F
※ 引述《adrianc (123)》之銘言: : ClassFather xxx = null; : if (str == "father) : { : xxx = new ClassFather(); : } : else if (str == "son") : { : xxx = new ClassSon(); : } 你的程式碼, 如果son沒繼承於father, 請問如何寫出 ClassFather xxx = new ClassSon(); ? 這段我跑起來跟本不行, 如果可以的話麻煩讓我看一下, 先不管誰寫的怎樣,我對這段寫法很感興趣,希望你可以教我這段。 : ※ 引述《LetsGoToEat (一起去吃東西吧)》之銘言: : : private void button1_Click(object sender, EventArgs e) : : { : : string str = file.ReadLine(); : : if (str == "father") : : { : : ClassFather xxx = new ClassFather(); : : IamFunction(file, xxx); : : } : : else if (str == "son") : : { : : ClassSon xxx = new ClassSon(); : : IamFunction(file, xxx); : : } 原PO的, 他很清楚知道Father跟Son不同的類別。

05/19 15:37, , 16F
真的要說 了不起是"偷懶" 延用了既有類別
05/19 15:37, 16F

05/19 15:42, , 17F
最後 用抽象隔離實作是個好的習慣 但不代表永遠可以拿
05/19 15:42, 17F

05/19 15:43, , 18F
一句話就說別人寫錯 (更何況這句話本身就有問題)
05/19 15:43, 18F

05/19 15:44, , 19F
不然 你直接批我變數用 xxx strA 會不會比較快?
05/19 15:44, 19F
framwork有類別繼承類別,這我之前就看過,但它寫的我不認為有錯, 因為framwork的繼承很明顯是is的關係。 要筆戰也很無聊,而且比這根本沒意義, 單純看到問題就點出,沒啥意思, 另外,謝謝提醒streamReader的問題,寫的時候的確沒想到。 另外, 可以的話麻煩告訴我,不用繼承的話如何寫出這段, ClassFather xxx = new ClassSon(); 這段我承認我看不懂。 ※ 編輯: StupidGaGa (60.249.117.38), 05/19/2014 16:16:38

05/19 16:20, , 20F
話說大哥 你看到 IamFunction 的簽名了沒?
05/19 16:20, 20F

05/19 16:21, , 21F
你是沒看到還是真的看不懂?
05/19 16:21, 21F

05/19 16:22, , 22F
那個簽名已經知道他的 son 有繼承 father 了....
05/19 16:22, 22F

05/19 16:23, , 23F
還是看不懂簽名? signature?
05/19 16:23, 23F
那段看過了, 原PO沒意外是有用繼承。 但你寫的範例如果沒用繼承的話,我也跑不起來。 你也說你寫的範例中沒有包括son繼承father, 所以你寫的範例son有沒有繼承faher? 如果有,你自己也清楚這樣範例不太好, 如果沒有,就很奇怪了。 ※ 編輯: StupidGaGa (60.249.117.38), 05/19/2014 16:28:56

05/19 16:25, , 24F
你不覺得msdn有錯 卻覺得這裡的Son繼承Father 有錯 理由?
05/19 16:25, 24F

05/19 16:26, , 25F
不要問這麼大的好了 這裡的son和father各是什麼類別
05/19 16:26, 25F

05/19 16:27, , 26F
你知道嗎? 我不清楚 因為就我看到的內容為限 只看到屬性
05/19 16:27, 26F

05/19 16:29, , 27F
所以 以內容為限 son繼承father 可能有錯 也可能沒錯
05/19 16:29, 27F

05/19 16:30, , 28F
所以在沒有更多已知的情況下 我覺得你的指教很無厘頭
05/19 16:30, 28F

05/19 16:33, , 29F
上面寫的5剛好被你的補充切成兩段
05/19 16:33, 29F

05/19 16:34, , 30F
"我寫的"範例中不包括繼承 但我有延用"既有的"類別
05/19 16:34, 30F

05/19 16:34, , 31F
也就是說 這是一段不改變類別設計為前提的範例
05/19 16:34, 31F

05/19 16:39, , 32F
不改變設計的原因是 以目前看到的內容為限
05/19 16:39, 32F

05/19 16:40, , 33F
沒辦法判斷 son和father 的繼承關係是不是合理
05/19 16:40, 33F

05/19 16:43, , 34F
言歸正傳 原PO的問題是要避免重覆程式碼
05/19 16:43, 34F

05/19 16:43, , 35F
結果改完後在 if 和 else 中都出現了都樣的呼叫
05/19 16:43, 35F

05/19 16:45, , 36F
既然都已經繼承了 所以我單純寫出一點修正來避開這個問題
05/19 16:45, 36F

05/19 16:46, , 37F
完全看不出你回一篇文在激動什麼 DesignPattern 的 = =
05/19 16:46, 37F

05/19 16:54, , 38F
如果你還是覺得這個例子中是錯的 麻煩幫我
05/19 16:54, 38F

05/19 16:55, , 39F
把son/father換成label/control, strA/strB換name/text
05/19 16:55, 39F

05/19 16:56, , 40F
再幫忙寫個信問MS 為什麼Label可以繼承非抽象類別Control
05/19 16:56, 40F
你的例子舉錯了, 為什麼我會說MS類別繼承類別我認同, 是因為他的繼承有is的關係在, label is control,form is control,這種繼承是OK的, (labal是控制項,from是控制項。) 反過來看, father跟son單就類別名字來看不太是is的關係, 難道你會認為,你是你父親? 難道你會認為,label is form? 你可以看看下列描述, 1. 兒子是家人,父親是家人,label是控制項,form是控制項 2. 兒子是父親,label是form 你認為哪個比較好? 你如果仔細看看,MS裡的繼承都是is的關係, 至少我trace過的都這樣, 如果你有不認同MS的繼承關係,麻煩告訴我,我很有興趣。 許多人錯用繼承是因為like的關係, 一旦有這種關係在就必須要抽像然後建立一個基底類別來繼承, 例如, 跑車跟卡車不是is的關係,是like, father跟son也不是is的關係,是like。 你跟我只是兩點看法不同 1. 也許你會說沒看到內容不確定他們的關係, 但我認為,命名本身就是重要的一點, 單純看到father跟son我就當下認為是like所以我會抽像, 你會認為沒什麼或不確定,就直接繼承,其實很多人都這樣。 2. 你認為在最小幅度內更動原PO程式碼, 我認為要把正確的觀念交給原PO,所以我連原PO的程式碼也有保留起來, 單純只是看法上的不同而已 說穿了,你如果要這樣教也可以, 但我無法這樣教,繼承這種基礎概念反而是最需要釐清的。 程式這東西本來就是經驗與知識的累積, 你可以不認同,因為你有你的知識跟經驗,這是正確的, 任何知識本來就要經過判斷才吸收。

05/19 17:22, , 41F
先不管son father這些名稱,為什麼類別不應該繼承類別?
05/19 17:22, 41F

05/19 18:14, , 42F
純推討論@@
05/19 18:14, 42F

05/19 21:36, , 43F
話說使用介面和繼承基底類別到底差在哪?
05/19 21:36, 43F

05/19 21:39, , 44F
偶合性強弱的差別吧 樓上
05/19 21:39, 44F
應該說 介面 跟 抽像類別 吧!? 看的角度有很多,網路上也有許多人在討論兩種的差異。 我個人也有不同解釋,根據學到經驗也會有更多不同的解釋, 搞不好三年後我又有不同解釋,不過這東西怎麼解釋都算對。 介面是對行為的抽象,可抽拔的,弱耦合 抽象類別是對類別的抽象,不可抽拔的,強耦合。 (也有人認為,C#把多重繼承取消,所以介面是頂替多重繼承。) 以介面來舉例的話,我會推4.5有的Iobserver跟Iobserverble, 任何class我想做觀察者模式,就加上這兩個介面, 不想要的時候我就拔掉。 抽象類別的話,可以看Button跟ButtonBase。 不管名稱或是成員,擺明就是強耦合。 通常是用在對一整個類別群的抽象或某一個特定的類別上。

05/20 00:41, , 45F
類別繼承類別沒有問題吧,隨便建一個winform方案,都是
05/20 00:41, 45F

05/20 00:44, , 46F
form1:form 在"深入淺出C#"中舉例,蜜蜂有工蜂(CLASS),
05/20 00:44, 46F

05/20 00:50, , 47F
"介面與防止重覆程式碼無關,而是跟讓一個類別可以應用
05/20 00:50, 47F

05/20 00:54, , 48F
在多種情況有關。
05/20 00:54, 48F
先推深入淺出這本書,入門的好書。 form1:form 基本上是把form當基底類別使用了, 相信很多人是 new form1(),而不是 new form(),這差很多。 基底類別通常都不會產生實體(new),是單純拿來繼承用的, (基底類別可以是介面、抽向類別、類別) 如同我上面的family如果用類別不用抽象類別可不可以, 當然可以,但我不會拿他來產生實體(new family())。 類別不能繼承類別,有幾個情況下才能打破, 1. 繼承至「同一個」基底類別,基底類別不會拿來new 2. is 的關係 3. 自己依情況打破 (其實應該講「類別不該繼承至衍生類別」,這比較符合我要說的原意) (不過基底類別能成為抽象的話我都會用抽像類別或介面) 如果繼承關係畫成樹狀圖的話, 通常root是基底類別,只拿來繼承, leaf是衍生類別,拿來作實體,不會拿來繼承。 而且說實在的,原則有很多,不管什麼SOLID或是其他的, 該怎麼根據實際情況而取捨本來就是工程師的工作之一, 世上不可能有100%遵從所有原則的程式,只有經過取捨後的程式, 但原PO的例子是要抽像沒錯,且不要類別繼承類別。 實作上我也會用到類別繼承類別,但我繼承的是同一個基底類別, 我不會拿衍生類別繼承衍生類別。 假設我有3個固定的view,那這3個我會繼承至Form。 以下兩種繼承可以看看差別 1. From1:Form Form2:Form Form3:Form 2. Form1:From Form2:From1(類別繼承衍生類別) Form3:Form2(類別繼承衍生類別) 很明顯第二種繼承就是壞繼承,但很不幸的這種繼承很常見, 尤其程式經過多次不同人的維護後,這種情況很容易發生。 (如果去掉form這種常見的東西,自定義的類別很常出現衍生類別繼承衍生類別) 類別要繼承類別,最好繼承至同一個基底類別, 如果以原PO例子看看哪個比較好。 1. Father:Family Son:Family 2. Son:Father 說實在的, 討論這也只是自爽用的,老闆才不會管你用啥方式, 只要會跑就好,不會掛掉就好, 我想這是每一個工程師的心酸所在。 在怎麼嘴砲,也不如手上白花花的銀子還實在。 ※ 編輯: StupidGaGa (60.249.117.38), 05/20/2014 11:24:32

05/20 12:59, , 49F
這叫做工程師的浪漫
05/20 12:59, 49F

05/20 13:32, , 50F
巨大機器人(變形金剛)與巨大怪獸(哥吉拉)是男人的浪漫
05/20 13:32, 50F

05/21 09:12, , 51F
IntegerTextBox : FormattedTextBox : TextBox : Control
05/21 09:12, 51F

05/21 09:13, , 52F
例你Form那個例子,你覺得這是壞繼承?
05/21 09:13, 52F

05/21 09:13, , 53F
要繼承就是要省掉同樣的部分,為什麼還要特地從基底繼承?
05/21 09:13, 53F

05/21 09:13, , 54F
你說有幾個情況才能打破的 2 is的關係
05/21 09:13, 54F

05/21 09:14, , 55F
繼承本來大多數就是因為is的關係才繼承,怎麼變例外了?
05/21 09:14, 55F

05/23 00:13, , 56F
觀念很好很棒,但是拿原PO的例子根本矯枉過正...
05/23 00:13, 56F
文章代碼(AID): #1JUQ50ya (C_Sharp)
文章代碼(AID): #1JUQ50ya (C_Sharp)