系列文章導航:
四大發明之活字印刷——面向對象思想的勝利
小菜編程成長記(一 面試受挫——代碼無錯就是好?)
小菜編程成長記(二 代碼規范、重構)
小菜編程成長記(三 復制VS復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂!)
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面!)
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
(續上篇)
小菜心里想:“大鳥要我做的是一個商場收銀軟件,營業員根據客戶購買商品單價和數量,向客戶收費。這個很簡單,兩個文本框,輸入單價和數量,再用個列表框來記錄商品的合計,最終用一個按鈕來算出總額就可,對,還需要一個重置按鈕來重新開始,不就行了?!”
代碼樣例(可使用):
商場收銀系統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復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂!)
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面!)
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
“這下可以了吧,只要我事先把商場可能的打折都做成下拉選擇框的項,要變化的可能性就小多了。”小菜說道。
“這比剛才靈活性上是好多了,不過重復代碼很多,像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復用)
小菜編程成長記(四 業務的封裝)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(五 體會簡單工廠模式的美妙)
小菜編程成長記(六 工廠不好用了?)
小菜編程成長記(七 用“策略模式”是一種好策略)
小菜編程成長記(八 反射——程序員的快樂!)
小菜編程成長記(九 會修電腦不會修收音機?——聊設計模式原則)
小菜編程成長記(十 三層架構,分層開發)
小菜編程成長記(十一 無熟人難辦事?——聊設計模式迪米特法則)
小菜編程成長記(十二 有了門面,程序員的程序會更加體面!)
小菜編程成長記(十三 設計模式不能戲說!設計模式怎就不能戲說?)
“大鳥,搞定,這次無論你要怎么改,我都可以簡單處理就行了。”小菜自信滿滿的說。
“是嗎,我要是需要打5折和滿500送200的促銷活動,如何辦?”
“只要在現金工廠當中加兩個條件,在界面的下拉選項框里加兩項,就OK了。”
“現金工廠?!你當是生產鈔票呀。是收費對象生成工廠才準確。說得不錯,如果我現在需要增加一種商場促銷手段,滿100積分10點,以后積分到一定時候可以領取獎品如何做?”
“有了工廠,何難?加一個積分算法,構造方法有兩個參數:條件和返點,讓它繼承CashSuper,再到現金工廠,哦,不對,是收—費—對—象—生—成—工—廠里加滿100積分10點的分支條件,再到界面稍加改動,就行了。”
“嗯,不錯,那我問你,如果商場現在需要拆遷,沒辦法,只能跳樓價銷售,商場的所有商品都需要打8折,打折后的價錢再每種商品滿300送50,最后計總價的時候,商場還滿1000送200,你說如何辦?”
“搞沒搞錯哦,這商場不如白送得了,哪有這樣促銷的?老板跳樓時估計都得赤條條的了。”
“商場大促銷你還不高興呀!當然,你是軟件開發者,客戶老是變動需求的確不爽,但你不能不讓客戶提需求呀,我不是說過嗎,需求的變更是必然!所以開發者應該的是考慮如何讓自己的程序更能適應變化,而不是抱怨客戶的無理,客戶不會管程序員加班時的汗水
,也不相信程序員失業時的眼淚
,因為客戶自己正在為自己的放血甩賣而流淚呀。”
大鳥接著說:“簡單工廠模式雖然也能解決這個問題,但的確不是最好的辦法,另外由于商場是可能經常性的更改打折額度和返利額度,每次更改都需要改寫代碼重新編譯部署真的是很糟糕的處理方式,面對算法的時常變動,應該有更好的辦法。好好去研究一下設計模式吧,推薦你看一本書,《深入淺出設計模式》,或許你看完第一章,就會有解決辦法了。
”
小菜進入了沉思中……
(待續)本例C#源代碼
另:建議大家去閱讀《深入淺出設計模式》,第一章下載,本人非常喜歡這本書的風格,這是真正的做到了深入淺出呀。我也希望自己可以用類似的方式講述問題。
本文還有一個用意是對一些初學者,可以考慮一下大鳥提出的問題,在我的下一篇《小菜編程成長記八》出來之前,改寫我的源代碼,實現更靈活更方便的商場收銀程序共享給大家討論,或許您寫的東東比我寫的還要好,那樣就大家都有提高了。程序不是看出來的,是寫出來的。好好加油!
NET技術:小菜編程成長記(六 工廠不好用了?),轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。