C#: switch语句的重构
生活随笔
收集整理的這篇文章主要介紹了
C#: switch语句的重构
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
switch語句是我們?nèi)粘9ぷ髦凶畛R娨彩菭幷撟疃嗟?#xff08;goto被忽視的前提下)。在重構(gòu)中也把switch語句看成是一種代碼的壞味道。但如何改造現(xiàn)有的switch代碼并在今后去避免呢?本文從兩方面進行探討。 1 類型轉(zhuǎn)化?
??? 在不同的抽象層次上對于同一個對象可能會用不同的定義。舉個簡單的例子,在計算器中,用戶輸入的操作符號可能是字符型的,而程序內(nèi)部實現(xiàn)的時候需要用枚舉型。因此可能就會有這樣的函數(shù)。?
public?class?Calculator?
? ? ? ? {?
????????????????public?enum?OPERATOR {Add, Minus, Multiply, Divide, Unknown};
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? OPERATOR op = OPERATOR.Unknown;
? ? ? ? ? ? ? ? ? ? ? ??switch?(ch)?
? ? ? ? ? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'+':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Add;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'-':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Minus;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'*':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Multiply;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'/':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Divide;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??default:?
? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? }?
? ? ? ? ? ? ? ? ? ? ? ??return?op;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 代碼不長,不過寫的過程中我卻拷貝幾次(case部分的代碼)。原因就是代碼的結(jié)構(gòu)性重復(fù)還是比較嚴重的,而且如果以后支持其他新的操作時候,這代碼不僅要改變,而且還會不斷變?nèi)唛L。認真想想,避免的辦法還是有的,用Dictionary做一個映射表就可以實現(xiàn)。?
? public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??public?enum?OPERATOR { Add, Minus, Multiply, Divide, Unknown};
? ? ? ? ? ? ? ??static?private?var OperatorMap =?new?Dictionary<char, OPERATOR> {?
? ? ? ? ? ? ? ? ? ? ? ? { '+', OPERATOR.Add },?
? ? ? ? ? ? ? ? ? ? ? ? { '-', OPERATOR.Minus },?
? ? ? ? ? ? ? ? ? ? ? ? { '*', OPERATOR.Divide },?
? ? ? ? ? ? ? ? ? ? ? ? { '/', OPERATOR.Multiply },?
? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator2(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??if?(OperatorMap.ContainsKey(ch))?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OperatorMap[ch];?
? ? ? ? ? ? ? ? ? ? ? ??else?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OPERATOR.Unknown;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 這樣,不僅代碼簡潔了很多,而且從本質(zhì)上已經(jīng)從邏輯代碼維護變成了映射表的維護。 2 動作調(diào)用?
接續(xù)剛才的例子,這次不僅要實現(xiàn)操作符轉(zhuǎn)化,而且要實現(xiàn)真正的運算。第一個反應(yīng)又是想到了switch。實現(xiàn)如下:
? public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??static?public?int?Calculate(char?op,?int?number1,?int?number2)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??int?result = 0;
? ? ? ? ? ? ? ? ? ? ? ??switch?(GetOperator(op))?
? ? ? ? ? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Add:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 + number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Minus:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 - number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Multiply:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 * number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Divide:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 / number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??default:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??throw?new?Exception("Unsupported Operation!");?
? ? ? ? ? ? ? ? ? ? ? ? }?
? ? ? ? ? ? ? ? ? ? ? ??return?result;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 跟之前遇到的問題有些類似,不過這回需要調(diào)用函數(shù)。通過.Net環(huán)境提供的Dictionary以及Func Delegate的解決如下:?
public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??static?private?Dictionary<OPERATOR, Func<int,?int,?int>> calculationAction =?new?Dictionary<OPERATOR, Func<int,?int,?int>> {?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Add, Add },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Minus, Minus },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Multiply, Multiply },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Divide, Divide }????????????
? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator2(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??if?(OperatorMap.ContainsKey(ch))?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OperatorMap[ch];?
? ? ? ? ? ? ? ? ? ? ? ??else?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OPERATOR.Unknown;?
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ??static?int?Add(int?number1,?int?number2)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??return?number1 + number2;?
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ??// Others are omitted here for brevity?
? ? ? ? } 通過這個簡單的例子,我們可以看出Switch通常會帶來一些結(jié)構(gòu)性的重復(fù),通過利用Dictionary等二維表結(jié)構(gòu),我們可以盡量去避免switch語句,從而實現(xiàn)更好的靈活性和可維護性。最后需要支持的是,在Switch語句的重構(gòu)過程中需要注意幾點: * 共通化以使得各個case中調(diào)用函數(shù)的簽名一致?
* if...else if...else結(jié)構(gòu)同switch在某些情況下具有互換性,也可以考慮這種方法?
* switch語句的重構(gòu)是也可以考慮State Pattern以及Strategy Pattern等設(shè)計模式。選擇的時候可以考慮視具體情況而定。
??? 在不同的抽象層次上對于同一個對象可能會用不同的定義。舉個簡單的例子,在計算器中,用戶輸入的操作符號可能是字符型的,而程序內(nèi)部實現(xiàn)的時候需要用枚舉型。因此可能就會有這樣的函數(shù)。?
public?class?Calculator?
? ? ? ? {?
????????????????public?enum?OPERATOR {Add, Minus, Multiply, Divide, Unknown};
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? OPERATOR op = OPERATOR.Unknown;
? ? ? ? ? ? ? ? ? ? ? ??switch?(ch)?
? ? ? ? ? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'+':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Add;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'-':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Minus;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'*':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Multiply;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?'/':?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? op = OPERATOR.Divide;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??default:?
? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? }?
? ? ? ? ? ? ? ? ? ? ? ??return?op;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 代碼不長,不過寫的過程中我卻拷貝幾次(case部分的代碼)。原因就是代碼的結(jié)構(gòu)性重復(fù)還是比較嚴重的,而且如果以后支持其他新的操作時候,這代碼不僅要改變,而且還會不斷變?nèi)唛L。認真想想,避免的辦法還是有的,用Dictionary做一個映射表就可以實現(xiàn)。?
? public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??public?enum?OPERATOR { Add, Minus, Multiply, Divide, Unknown};
? ? ? ? ? ? ? ??static?private?var OperatorMap =?new?Dictionary<char, OPERATOR> {?
? ? ? ? ? ? ? ? ? ? ? ? { '+', OPERATOR.Add },?
? ? ? ? ? ? ? ? ? ? ? ? { '-', OPERATOR.Minus },?
? ? ? ? ? ? ? ? ? ? ? ? { '*', OPERATOR.Divide },?
? ? ? ? ? ? ? ? ? ? ? ? { '/', OPERATOR.Multiply },?
? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator2(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??if?(OperatorMap.ContainsKey(ch))?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OperatorMap[ch];?
? ? ? ? ? ? ? ? ? ? ? ??else?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OPERATOR.Unknown;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 這樣,不僅代碼簡潔了很多,而且從本質(zhì)上已經(jīng)從邏輯代碼維護變成了映射表的維護。 2 動作調(diào)用?
接續(xù)剛才的例子,這次不僅要實現(xiàn)操作符轉(zhuǎn)化,而且要實現(xiàn)真正的運算。第一個反應(yīng)又是想到了switch。實現(xiàn)如下:
? public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??static?public?int?Calculate(char?op,?int?number1,?int?number2)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??int?result = 0;
? ? ? ? ? ? ? ? ? ? ? ??switch?(GetOperator(op))?
? ? ? ? ? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Add:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 + number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Minus:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 - number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Multiply:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 * number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??case?OPERATOR.Divide:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result = number1 / number2;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??break;?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??default:?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??throw?new?Exception("Unsupported Operation!");?
? ? ? ? ? ? ? ? ? ? ? ? }?
? ? ? ? ? ? ? ? ? ? ? ??return?result;?
? ? ? ? ? ? ? ? }?
? ? ? ? } 跟之前遇到的問題有些類似,不過這回需要調(diào)用函數(shù)。通過.Net環(huán)境提供的Dictionary以及Func Delegate的解決如下:?
public?class?Calculator?
? ? ? ? {?
? ? ? ? ? ? ? ??static?private?Dictionary<OPERATOR, Func<int,?int,?int>> calculationAction =?new?Dictionary<OPERATOR, Func<int,?int,?int>> {?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Add, Add },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Minus, Minus },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Multiply, Multiply },?
? ? ? ? ? ? ? ? ? ? ? ? { OPERATOR.Divide, Divide }????????????
? ? ? ? ? ? ? ? };
? ? ? ? ? ? ? ??public?static?OPERATOR GetOperator2(char?ch)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??if?(OperatorMap.ContainsKey(ch))?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OperatorMap[ch];?
? ? ? ? ? ? ? ? ? ? ? ??else?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??return?OPERATOR.Unknown;?
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ??static?int?Add(int?number1,?int?number2)?
? ? ? ? ? ? ? ? {?
? ? ? ? ? ? ? ? ? ? ? ??return?number1 + number2;?
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ??// Others are omitted here for brevity?
? ? ? ? } 通過這個簡單的例子,我們可以看出Switch通常會帶來一些結(jié)構(gòu)性的重復(fù),通過利用Dictionary等二維表結(jié)構(gòu),我們可以盡量去避免switch語句,從而實現(xiàn)更好的靈活性和可維護性。最后需要支持的是,在Switch語句的重構(gòu)過程中需要注意幾點: * 共通化以使得各個case中調(diào)用函數(shù)的簽名一致?
* if...else if...else結(jié)構(gòu)同switch在某些情況下具有互換性,也可以考慮這種方法?
* switch語句的重構(gòu)是也可以考慮State Pattern以及Strategy Pattern等設(shè)計模式。選擇的時候可以考慮視具體情況而定。
本文出自 “林家男孩” 博客,請務(wù)必保留此出處http://bj007.blog.51cto.com/1701577/345100
轉(zhuǎn)載于:https://www.cnblogs.com/zagelover/articles/2887113.html
總結(jié)
以上是生活随笔為你收集整理的C#: switch语句的重构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 控件不响应点击事件解决办法
- 下一篇: Lumia 800 7.10.8858.