系列文章導航:
四大發明之活字印刷——面向對象思想的勝利
小菜編程成長記(一 面試受挫——代碼無錯就是好?)
小菜編程成長記(二 代碼規范、重構)
小菜編程成長記(三 復制VS復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂?。?/a>
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面!)
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
(續上篇)
小菜心里想:“大鳥要我做的是一個商場收銀軟件,營業員根據客戶購買商品單價和數量,向客戶收費。這個很簡單,兩個文本框,輸入單價和數量,再用個列表框來記錄商品的合計,最終用一個按鈕來算出總額就可,對,還需要一個重置按鈕來重新開始,不就行了?!”
代碼樣例(可使用):
商場收銀系統v1.0關鍵代碼如下:

Code
//聲明一個double變量total來計算總計
double total = 0.0d;
private void btnOk_Click(object sender, EventArgs e)
{
//聲明一個double變量totalPrices來計算每個商品的單價(txtPrice)*數量(txtNum)后的合計
double totalPrices=Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text);
//將每個商品合計計入總計
total = total + totalPrices;
//在列表框中顯示信息
lbxList.Items.Add("單價:"+txtPrice.Text+" 數量:"+txtNum.Text+" 合計:"+totalPrices.ToString());
//在lblResult標簽上顯示總計數
lblResult.Text = total.ToString();
}
系列文章導航:
四大發明之活字印刷——面向對象思想的勝利
小菜編程成長記(一 面試受挫——代碼無錯就是好?)
小菜編程成長記(二 代碼規范、重構)
小菜編程成長記(三 復制VS復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂?。?/a>
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面!)
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
“這下可以了吧,只要我事先把商場可能的打折都做成下拉選擇框的項,要變化的可能性就小多了。”小菜說道。
“這比剛才靈活性上是好多了,不過重復代碼很多,像Convert.ToDouble(),你這里就寫了8遍,而且4個分支要執行的語句除了打折多少以外幾乎沒什么不同,應該考慮重構一下。不過還不是最主要的,現在我的需求又來了,商場的活動加大,需要有滿300返100的促銷算法,你說怎么辦?”
“滿300返100,那要是700就要返200了?這個必須要寫函數了吧?”
“小菜呀,看來之前教你的白教了,這里面看不出什么名堂嗎?”
“哦!我想起來了,你的意思是簡單工廠模式是吧,對的對的,我可以先寫一個父類,再繼承它實現多個打折和返利的子類,利用多態,完成這個代碼。”
“你打算寫幾個子類?”
“根據需求呀,比如8折、7折、5折、滿300送100、滿200送50……要幾個寫幾個。”
“小菜又不動腦子了,有必要這樣嗎?如果我現在要3折,我要滿300送80,你難道再去加子類?你不想想看,這當中哪些是相同的,哪些是不同的?”
“對的,這里打折基本都是一樣的,只要有個初始化參數就可以了。滿幾送幾的,需要兩個參數才行,明白,現在看來不麻煩了。”
“面向對象的編程,并不是類越多越好,類的劃分是為了封裝,但分類的基礎是抽象,具有相同屬性和功能的對象的抽象集合才是類 。打一折和打九折只是形式的不同,抽象分析出來,所有的打折算法都是一樣的,所以打折算法應該是一個類。好了,空話已說了太多,寫出來再是真的懂。”
大約1個小時后,小菜交出了第三份的作業
商場收銀系統v1.3關鍵代碼如下:

Code
//現金收取父類
abstract class CashSuper
{
//抽象方法:收取現金,參數為原價,返回為當前價
public abstract double acceptCash(double money);
}
//正常收費,繼承CashSuper
class CashNormal : CashSuper
{
public override double acceptCash(double money)
{
return money;
}
}
//打折收費,繼承CashSuper
class CashRebate : CashSuper
{
private double moneyRebate = 1d;
//初始化時,必需要輸入折扣率,如八折,就是0.8
public CashRebate(string moneyRebate)
{
this.moneyRebate = double.Parse(moneyRebate);
}
public override double acceptCash(double money)
{
return money * moneyRebate;
}
}
//返利收費,繼承CashSuper
class CashReturn : CashSuper
{
private double moneyCondition = 0.0d;
private double moneyReturn = 0.0d;
//初始化時必須要輸入返利條件和返利值,比如滿300返100,則moneyCondition為300,moneyReturn為100
public CashReturn(string moneyCondition, string moneyReturn)
{
this.moneyCondition = double.Parse(moneyCondition);
this.moneyReturn = double.Parse(moneyReturn);
}
public override double acceptCash(double money)
{
double result = money;
//若大于返利條件,則需要減去返利值
if (money >= moneyCondition)
result = money - Math.Floor(money / moneyCondition) * moneyReturn;
return result;
}
}
//現金收取工廠
class CashFactory
{
//根據條件返回相應的對象
public static CashSuper createCashAccept(string type)
{
CashSuper cs = null;
switch (type)
{
case "正常收費":
cs = new CashNormal();
break;
case "滿300返100":
CashReturn cr1 = new CashReturn("300", "100");
cs = cr1;
break;
case "打8折":
CashRebate cr2 = new CashRebate("0.8");
cs = cr2;
break;
}
return cs;
}
}
//客戶端窗體程序(主要部分)
CashSuper csuper;//聲明一個父類對象
double total = 0.0d;
private void btnOk_Click(object sender, EventArgs e)
{
//利用簡單工廠模式根據下拉選擇框,生成相應的對象
csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
double totalPrices=0d;
//通過多態,可以得到收取費用的結果
totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
total = total + totalPrices;
lbxList.Items.Add("單價:" + txtPrice.Text + " 數量:" + txtNum.Text + " "+cbxType.SelectedItem+ " 合計:" + totalPrices.ToString());
lblResult.Text = total.ToString();
}
系列文章導航:
四大發明之活字印刷——面向對象思想的勝利
小菜編程成長記(一 面試受挫——代碼無錯就是好?)
小菜編程成長記(二 代碼規范、重構)
小菜編程成長記(三 復制VS復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂?。?/a>
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面?。?/a>
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
“大鳥,搞定,這次無論你要怎么改,我都可以簡單處理就行了。”小菜自信滿滿的說。
“是嗎,我要是需要打5折和滿500送200的促銷活動,如何辦?”
“只要在現金工廠當中加兩個條件,在界面的下拉選項框里加兩項,就OK了。”
“現金工廠?!你當是生產鈔票呀。是收費對象生成工廠才準確。說得不錯,如果我現在需要增加一種商場促銷手段,滿100積分10點,以后積分到一定時候可以領取獎品如何做?”
“有了工廠,何難?加一個積分算法,構造方法有兩個參數:條件和返點,讓它繼承CashSuper,再到現金工廠,哦,不對,是收—費—對—象—生—成—工—廠里加滿100積分10點的分支條件,再到界面稍加改動,就行了。”
“嗯,不錯,那我問你,如果商場現在需要拆遷,沒辦法,只能跳樓價銷售,商場的所有商品都需要打8折,打折后的價錢再每種商品滿300送50,最后計總價的時候,商場還滿1000送200,你說如何辦?”
“搞沒搞錯哦,這商場不如白送得了,哪有這樣促銷的?老板跳樓時估計都得赤條條的了。”
“商場大促銷你還不高興呀!當然,你是軟件開發者,客戶老是變動需求的確不爽,但你不能不讓客戶提需求呀,我不是說過嗎,需求的變更是必然!所以開發者應該的是考慮如何讓自己的程序更能適應變化,而不是抱怨客戶的無理,客戶不會管程序員加班時的汗水
,也不相信程序員失業時的眼淚
,因為客戶自己正在為自己的放血甩賣而流淚呀。”
大鳥接著說:“簡單工廠模式雖然也能解決這個問題,但的確不是最好的辦法,另外由于商場是可能經常性的更改打折額度和返利額度,每次更改都需要改寫代碼重新編譯部署真的是很糟糕的處理方式,面對算法的時常變動,應該有更好的辦法。好好去研究一下設計模式吧,推薦你看一本書,《深入淺出設計模式》,或許你看完第一章,就會有解決辦法了。
”
小菜進入了沉思中……
(待續)本例C#源代碼
另:建議大家去閱讀《深入淺出設計模式》,第一章下載,本人非常喜歡這本書的風格,這是真正的做到了深入淺出呀。我也希望自己可以用類似的方式講述問題。
本文還有一個用意是對一些初學者,可以考慮一下大鳥提出的問題,在我的下一篇《小菜編程成長記八》出來之前,改寫我的源代碼,實現更靈活更方便的商場收銀程序共享給大家討論,或許您寫的東東比我寫的還要好,那樣就大家都有提高了。程序不是看出來的,是寫出來的。好好加油!
NET技術:小菜編程成長記(六 工廠不好用了?),轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。