通過深入繼承之抽象類和接口綜合分析及完整案列解說(一),我想大家已經認識到了知識共享的巨大力量了。我門上面看到的這些東西不 是我們任何一個人在短時間內就能夠總結出來的,但是大家一起總結,那結果就是這樣爽的。
我希望大家都能夠大方一點,別做得那麼 小氣,生怕自己知道的那點知識被別人知道了。飯碗就被別人搶了,事實上在跟人分享的過程中並不是一味的在付出,你同樣也會有收獲,無 論是幫別人解答疑問還是跟別人交流,就好象我在寫(或著說我是在復制別人的心得)一樣,看起來我是在無償的為大家做,事實上呢我同樣 的有收獲的,因為寫這個文章的時候我發現了很多我過去學和用中一之沒有注意到的死角,也發現很多更新,更好的技巧。
所以我相信 ,只要我門每個人都盡量的多跟人分享你所學,最終帶來的是大家的共同進步。在園裡我特別喜歡老趙(MSDN Web Cast的ASP.NET AJAX深入淺 出系列課程),Dflying Chen(AJAX系列書籍),張逸老師(軟件設計精要與模式,WCF),李會軍(新版設計模式)等同志,他門的書籍及文章我相信大 家看後都會受益非淺,他們在園裡的排名及貢獻是大家共同看到的。
也許大家發現了我上面給張逸叫老師,這是為什麼呢?上面列舉的 這些牛人中我就認識張逸,認識我的朋友可別說是我和他同姓才特別介紹,其實並不是這樣。在我的學習過程中張逸老師對我幫助很大,在我 大學即將畢業的最後一年裡,我在張老師所在的公司實習(他當時是我門.NET開發一部的部長,管人可嚴了,我悄悄說的,大家看到了這句話一定 是眼花了,呵呵),他曾經給我上很多課程和開過很多技術專題講座,我想大家都知道,對於一個沒畢業的大學生來說,沒有一定的項目開發經 驗在寫論文的時候是很吃力的,在我考系統分析師期間論文得到他的指導讓我考試順利通過,在此我借園子的位置想張老師說聲謝謝。另外他 所著的《軟件設計精要與模式》對我的幫助也很大,雖然這不是一本講解設計模式的專題書籍,他的寫作卻是以設計模式為主來講解的,最後 以MS開源項目PetShop 4.0作為案例講解模式的應用,個人覺得寫得很不錯,我在現在的項目中都采用了書裡的很多設計思想。
看到這 裡大家是不是覺得我這個人很羅嗦了,寫文章寫到去介紹牛人和書籍去了,這是不是在為他門打廣告????
好了,言歸正轉,我門還 是進入主題,戲不能唱一半就停止了吧,既然開始了那麼演得在差也得演唱完畢吧。看看下面這個實例:
我門根據一個小書店的情況來 說這個實例,當然實例不能准確的說明一切,只是說通過這個類讓大家更感性的認識到抽象類和接口的使用情況。
首先分析書店的經營 情況
1. 書是可以出祖和銷售的
2. 書的分類為三個方面,所以銷售和出祖的價格分別也分三個檔次
3. 顧客分為會員和 普通顧客
通過上面的分析,我們可以開始構思程序的實現了
1. 無論買那種折扣的書都需要支付書對應的現金購買
2. 無 論租那種書都需要支付對應的租金
3. 無論那種業務類型都需要返回出詳細信息(實際上應該是寫入數據庫)
4. 無論他的邏輯 是怎麼樣的,我們在前台處理的時候並不想也不需要知道那麼多,我們就希望用我們現在知道的信息直
接換取到應該的操作.
這兩個我們使用接口來定義返回的 錢 .
然後再定義一個接口方法來處理我們的寫入數據庫操作(這裡是返回出詳細信息)
接 下來把顧客類型,交易類型,書的類型以及租借類型(指是租書還是還書)分別做個枚舉
先來看一個UML圖,我相信比我用手敲鍵盤更容 易說清楚結構。
一. 定義枚舉及Money接口
1namespace EBook
2{
3 /**//// <summary>
4 /// 會員類型
5 /// </summary>
6 public enum U_Type
7 {
8 member, //會員
9 shopper, //零售\租顧客
10 }
11 /**//// <summary>
12 /// 書的類型
13 /// </summary>
14 public enum B_Type
15 {
16 novel, //小說
17 life, //生活類
18 magazine //雜志
19 }
20 /**//// <summary>
21 /// 交易類型
22 /// </summary>
23 public enum S_Type
24 {
25 sell, //出售
26 hire //出租
27 }
28 /**//// <summary>
29 /// 租借類型,租借,歸還
30 /// </summary>
31 public enum H_Type
32 {
33 rent,
34 back
35 }
36 /**//// <summary>
37 /// 定義一個接口,返回 本次交易的錢
38 /// 執行最後插入數據庫的操作
39 /// </summary>
40 public interface Money
41 {
42 double GetMoney();
43 string Execute();
44 }
45}
二. 實現借口 ,抽象出具體的邏輯方法,定義枚舉及內部成員
namespace EBook
{
/**//// <summary>
/// 實現接口 中返回錢的方法,並且定義一系列下面類都會用到的成員
/// 做為接口下的一個總承
/// </summary>
public abstract class Root : Money
{
protected U_Type _utype; //會員類型
protected B_Type _btype; //書的類型
protected S_Type _stype; //交易類型
protected string _bookname; //書名
protected string _uname; //用戶名
protected double _price; //書的定價
protected double _cash; //實際支付的現金,不管是租書還是還書還是買書,他都 會涉及到最終給了多少錢這個問題
public abstract double GetMoney();
public abstract string Execute();
}
/**//// <summary>
/// 作為銷售類的一個基類,這個類實際上並沒有做什麼工作,主要是針對接口和基類做了一些補充說明
/// </summary>
public abstract class Sell : Root
{
/**//// <summary>
/// 初始化該類
/// </summary>
/// <param name="un">用戶名</param>
/// <param name="bn">書名</param>
/// <param name="p">書的定價</param>
public Sell (string un, string bn, double p)
{
_uname = un;
_bookname = bn;
_price = p;
}
外露屬性 (定價,書名,用戶名)#region 外露屬性(定價,書名,用戶名)
/**//// <summary>
/// 獲取書的定價
/// </summary>
public double Price
{
get { return _price; }
}
/**//// <summary>
/// 獲取用戶名稱
/// </summary>
public string Uname
{
get { return _uname; }
}
/**//// <summary>
/// 獲取書的名稱
/// </summary>
public string Bname
{
get { return _bookname; }
}
#endregion
實現基類中的抽象方法以及將任務分派到下面的派生類去#region 實現基類中的抽象方法以及將任 務分派到下面的派生類去
/**//// <summary>
/// 實現基類的抽象方法,但是考慮到還需要再下級的派生類來完成
/// 所以我們選擇讓他調用其他能夠被派生類修改的方法
/// </summary>
/// <returns></returns>
public override double GetMoney()
{
return TGetMoney();
}
public override string Execute()
{
return TExecute();
}
/**//// <summary>
/// 在這裡我們並不處理,而 是叫給處理他的派生類來完成
/// </summary>
/// <returns></returns>
public virtual double TGetMoney()
{
return 0;
}
/**//// <summary>
/// 在這裡我們並不處理,而是叫給處理他的派生類來完 成
/// </summary>
/// <returns></returns>
public virtual string TExecute()
{
return "";
}
#endregion
}
/**//// <summary>
/// 作為租賃業務的一個基類,幫助 實現ROOT類並增加租賃相關的屬性和方法。
/// </summary>
public abstract class Hire : Root
{
系列的私 有字段#region 系列的私有字段
/**//// <summary>
/// 租賃天數
/// </summary>
protected int _day;
/**//// <summary>
/// 書的押金
/// </summary>
protected double _deposit;
#endregion
外露屬性(定價,書名,用戶名,天數,日租金)#region 外露屬性(定價,書名,用戶名,天數,日租金)
/**//// <summary>
/// 獲取書的定價
/// </summary>
public double Price
{
get { return _price; }
}
/**//// <summary>
/// 獲取用戶名稱
/// </summary>
public string Uname
{
get { return _uname; }
}
/**//// <summary>
/// 獲取書的名稱
/// </summary>
public string Bname
{
get { return _bookname; }
}
/**//// <summary>
/// 獲取或者設置租賃的天數
/// </summary>
public int Day
{
get { return _day; }
set { _day = value; }
}
/**//// <summary>
/// 獲取或者設置書的押金
/// </summary>
public double Deposit
{
get { return _deposit; }
set { _deposit = value; }
}
/**//// <summary>
/// 實收 的現金
/// </summary>
public double Cash
{
get { return _cash; }
set { _cash = value; }
}
#endregion
實現基類中的抽象方法以及將任務分派到下面的派生類去#region 實現基類中的抽象方法以及將任務分 派到下面的派生類去
/**//// <summary>
/// 實現基類的抽象方法,但是考慮到還需要再下級的派生類來完成
/// 所以我們選擇讓他調用其他能夠被派生類修改的方法
/// </summary>
/// <returns></returns>
public override double GetMoney()
{
return TGetMoney();
}
public override string Execute()
{
return TExecute();
}
/**//// <summary>
/// 在這裡我們並不處理,而是叫給處理他的派生類來完成
/// </summary>
/// <returns></returns>
public virtual double TGetMoney()
{
return 0;
}
/**//// <summary>
/// 在這裡我們並不處理,而是叫給處理他的派生類來完成
/// </summary>
/// <returns></returns>
public virtual string TExecute()
{
return "";
}
#endregion
}
}
篇幅限制,我不做太多的解說,我相信真實案例代碼的展示+你自己學習後的總結會比我解說得更 好。實現的類代碼如下:
實現買書的邏輯↓
namespace EBook
實現租書的邏輯↓
{
/**//// <summary>
/// 這 個類處理會員購買書,我們假設都只是買一本,要買多本的朋友自己想辦法,哈哈
/// </summary>
public class Buy : Sell
{
public Buy(B_Type bt, string un, string bn, double p)
: base(un, bn, p)
{
_btype = bt;
_uname = un;
_bookname = bn;
_price = p;
}
/**//// <summary>
/// 根據書的類型來定折扣 ,當然,這裡的折扣本來是應該從數據庫或者配置文件中取的,我們演示就固化到這裡
/// </summary>
/// <returns></returns>
public override double TGetMoney()
{
switch (_btype)
{
case B_Type.novel:
_cash = _price * 0.5;
break;
case B_Type.life:
_cash = _price * 0.8;
break;
default :
_cash = _price;
break;
}
return _cash;
}
/**//// <summary>
/// 執行插入 數據庫的操作,但是我們這裡不需要,只要把結果顯示出來
/// 所以我們讓他給我們返回一句話就OK了。
/// </summary>
/// <returns></returns>
public override string TExecute()
{
return "尊 敬的會員:" + _uname + ",您購買《" + _bookname + "》,定價為:" + _price + ",折扣後為:" + GetMoney().ToString();
}
}
/**//// <summary>
/// 增加有個處理零售客戶的類,大致邏輯是一樣的,只是 說折扣不同
/// </summary>
public class SBuy : Sell
{
public SBuy(B_Type bt, string un, string bn, double p)
: base(un, bn, p)
{
_btype = bt;
_uname = un;
_bookname = bn;
_price = p;
}
/**//// <summary>
/// 根據書的類型來定折扣,當然,這裡的折扣本來是應該從數據庫或者配置文件中取的,我們演示 就固化到這裡
/// </summary>
/// <returns></returns>
public override double TGetMoney()
{
switch (_btype)
{
case B_Type.novel:
_cash = _price * 0.6;
break;
case B_Type.life:
_cash = _price * 0.9;
break;
default :
_cash = _price;
break;
}
return _cash;
}
/**//// <summary>
/// 執行插入數據庫的操作,但是我們這裡不需要,只要把結果顯示出來
/// 所以我們讓他給我們返 回一句話就OK了。
/// </summary>
/// <returns></returns>
public override string TExecute()
{
return "尊敬的顧客:" + _uname + ",您購買《" + _bookname + "》,定價為:" + _price + ",折扣後為:" + GetMoney().ToString();
}
}
}
namespace EBook
定義工廠類,處理按照會員類型返回具體的類
{
/**//// <summary>
/// 租書
/// 分析:租書的時候是不需要支付租金的,但是需要支付押金
/// </summary>
public class Rent : Hire
{
/**//// <summary>
/// 初始化對象
/// </summary>
/// <param name="un">用戶名</param>
/// <param name="bn">書 名</param>
/// <param name="p">書的定價</param>
public Rent(string un, string bn, double p)
{
_uname = un;
_bookname = bn;
_price = p;
}
public override double TGetMoney ()
{//直接返回實際支付的現金
return _cash;
}
/**//// <summary>
/// 將顧客支付的押金寫入數據庫, 這裡我們是打印出來
/// </summary>
/// <returns></returns>
public override string TExecute()
{
return "尊敬的顧客,您租借《" + _bookname + "》,本書定價為:" + _price + "元,請支付押金 " + _price + "元,實際支付" + TGetMoney().ToString() + "元";
}
}
/**//// <summary>
/// 會員還書
/// 分析:還書的時候需要退還押金並支付租金,我們直接把租金在押金裡面硬性扣除
/// 不 同的是這個是會員還書,所以租金和普通顧客的租金有區別
/// </summary>
public class M_Back : Hire
{
/**//// <summary>
/// 初始化對象
/// </summary>
/// <param name="un">用戶名 </param>
/// <param name="bn">書名</param>
/// <param name="day">租賃天 數</param>
/// <param name="bt">書的類型</param>
public M_Back(string un, string bn, int day, B_Type bt)
{
_uname = un;
_bookname = bn;
_day = day;
_btype = bt;
}
public override double TGetMoney()
{//直接返回應找零現金
return _deposit - GetRent();
}
/**//// <summary>
/// 計算書的租金
/// </summary>
/// <returns></returns>
private double GetRent()
{
switch (_btype)
{
case B_Type.novel:
_cash = Convert.ToDouble(_day) * 0.1;
break;
case B_Type.life:
_cash = Convert.ToDouble(_day) * 0.5;
break;
case B_Type.magazine:
_cash = Convert.ToDouble(_day) * 0.1;
break;
}
return _cash;
}
/**//// <summary>
/// 將顧客支付 的押金寫入數據庫,這裡我們是打印出來
/// </summary>
/// <returns></returns>
public override string TExecute()
{
return "尊敬的顧客,您租借《" + _bookname + "》,共計:" + _day + "天,已 支付押金" + _deposit + ",實際產生租金" + GetRent() + "元,應找您" + TGetMoney() + "元 ";
}
}
/**//// <summary>
/// 普通顧客還書
/// 分析:還書的時候需要退還押金並支付租金 ,我們直接把租金在押金裡面硬性扣除
/// </summary>
public class S_Back : Hire
{
/**//// <summary>
/// 初始化對象
/// </summary>
/// <param name="un">用戶名 </param>
/// <param name="bn">書名</param>
/// <param name="day">租賃天 數</param>
/// <param name="bt">書的類型</param>
public S_Back(string un, string bn, int day, B_Type bt)
{
_uname = un;
_bookname = bn;
_day = day;
_btype = bt;
}
/**//// <summary>
/// 直接應該退給顧客多少錢
/// </summary>
/// <returns></returns>
public override double TGetMoney()
{//直接返回應該找零的現金,已交的押金減去實際的租金
return _deposit - GetRent ();
}
/**//// <summary>
/// 計算書的租金
/// </summary>
/// <returns></returns>
private double GetRent()
{
switch (_btype)
{
case B_Type.novel:
_cash = Convert.ToDouble(_day) * 0.5;
break;
case B_Type.life:
_cash = Convert.ToDouble(_day) * 1d;
break;
case B_Type.magazine:
_cash = Convert.ToDouble(_day) * 0.3;
break;
}
return _cash;
}
/**//// <summary>
/// 將顧客支付的押金寫入數據庫,這裡我們是打印出來
/// </summary>
/// <returns></returns>
public override string TExecute()
{
return "尊敬的顧客,您租借《" + _bookname + "》,共計:" + _day + "天,已支付押金" + _deposit + ",實際產生租金" + GetRent() + "元,應找您" + TGetMoney() + "元";
}
}
}
using EBook;
/**//// <summary>
/// 工廠類主要是按照會員類型將具體使用那個類返回出去
/// </summary>
public class Factory
{
private U_Type _utype; //會員類型
private B_Type _btype; // 書的類型
private S_Type _stype; //交易類型
private H_Type _htype; //是租書還是還書
private string _bookname; //書名
private string _uname; //用戶名
private double _price; //書的定價
private int _day; //租借的天數
public Factory(U_Type ut,B_Type bt,S_Type st, string bn,string un,double p)
{
_utype = ut;
_btype = bt;
_stype = st;
_bookname = bn;
_uname = un;
_price = p;
}
/**//// <summary>
/// 因為這個並不參與到最初的類實例化中去
/// 比如是買書,那根本談不上是租還是還,所以單獨列出來
/// </summary>
public H_Type Htype
{
get { return _htype; }
set { _htype = value; }
}
public int Day
{
get { return _day; }
set { _day = value; }
}
/**//// <summary>
/// 根 據交易類型來判斷給那一個方法處理
/// </summary>
/// <returns></returns>
public Root HorS()
{
if(_stype==S_Type.hire)
return GetHire();
else
return GetBuy();
}
/**//// <summary>
/// 根據會員的類型來判斷返回那一個被初始化的類
/// </summary>
/// <returns></returns>
private Sell GetBuy()
{
if(_utype==U_Type.member)
return new Buy(_btype, _uname, _bookname, _price);
else
return new SBuy(_btype, _uname, _bookname, _price);
}
/**//// <summary>
/// 根據是租書還是還書(又判斷顧客類型)來初始化對應的類
/// </summary>
/// <returns></returns>
private Hire GetHire()
{
if (_htype == H_Type.rent)
return new Rent (_uname, _bookname, _price);
else
{
if (_utype == U_Type.member)
return new M_Back(_uname, _bookname, _day, _btype);
else
return new S_Back(_uname, _bookname, _day, _btype);
}
}
}
到 這裡為止,我們這個書店的程序邏輯就設計完畢了。
篇幅限制,具體的調用我就不多做解說,歡迎大家一起探討,學習。