今天回家一開燈感覺客廳的燈暗了許多,擡頭一看原來是燈泡快壞了,想想這個燈泡也是老式的不如換個新的節能燈泡算了。於是跑到小區對面的德爾泰市場買了同樣接口的節能燈泡,這樣光線又好又可以爲自己節約電費,回來後迅速拿起凳子,換了新燈泡感覺亮堂了許多。高興之餘就想用代碼去模擬一下這個場景。
1、案例設想
設想如果我們編寫一個程序通過聲控感應設備去控制燈光的顯示,那麼如何實現呢?我想首先第一步就是需要設計當感應設備捕獲到人的時候如何處理,第二部就是在處理內部控制燈泡發光,例如聲控設備感應到人的時候,控制我們平時的普通燈泡去發光。通過面向對象封裝模擬的代碼如下:
- static void Main(string[] args)
- {
- //是否感應到人 默認是
- bool isOpen = true;
- //普通燈泡
- Bulb bulb = new Bulb();
- //感應是否生效
- if (isOpen)//默認生效
- {
- //感應器控制燈泡發光
- Induction induction = new Induction();
- induction.Open(bulb);
- }
- }
- /// <summary>
- /// 感應器
- /// </summary>
- public class Induction
- {
- //打開終端(燈泡)
- public void Open(Bulb bulb)
- {
- //發光
- bulb.Luminescence();
- }
- }
- //燈泡
- public class Bulb
- {
- //發光
- public void Luminescence()
- {
- //燈泡發光的實現
- }
- }
那麼這個時候,我又想起了開始我燈泡壞了的事情了,我最後換了個節能的燈泡。那麼我在用代碼模擬一個節能燈泡的類吧。代碼如下:
- //節能燈泡
- public class FrugalBulb
- {
- //節能發光
- public void FrugalLuminescence()
- {
- //節能燈泡發光的實現
- }
- }
那麼這個時候我的普通燈泡壞了,爲了考慮成本,決定將普通的燈泡替換成節能燈泡,那麼就會出現一個問題,當普通燈泡的插孔與節能燈泡的插孔不同時?我們需要將燈泡的插孔也替換掉,並且感應器也要增加對應節能燈泡的調用,這樣就大大的增加了替換的成本,不好的替換方式用代碼模擬實現如下:
- static void Main(string[] args)
- {
- //是否感應到人 默認是
- bool isOpen = true;
- //普通燈泡
- Bulb bulb = new Bulb();
- //節能燈泡
- FrugalBulb fBulb = new FrugalBulb();
- //感應是否生效
- if (isOpen)//默認生效
- {
- //感應器控制燈泡發光
- Induction induction = new Induction();
- //拆除原先普通燈泡的接口
- //induction.Open(bulb);
- //增加節能燈泡的接口
- induction.OpenFrugal(fBulb);
- }
- }
- /// <summary>
- /// 感應器
- /// </summary>
- public class Induction
- {
- //打開終端(燈泡)
- public void Open(Bulb bulb)
- {
- //發光
- bulb.Luminescence();
- }
- //打開節能終端(燈泡)
- public void OpenFrugal(FrugalBulb fBulb)
- {
- //加入節能發光的調用
- fBulb.FrugalLuminescence();
- }
- }
這樣的話實際生活中我們替換增加了成本,代碼模擬中我們修改了原先的代碼頁增加了成本,那麼如何降低這些成本呢?
2、引入工廠
分析了上面的內容,我們可以看出的問題有:燈泡實際上都是發光,但是發光的接口不一樣例如:普通燈泡發光調用的是【Luminescence】而節能燈泡發光需要調用【FrugalLuminescence】,如果今後需要替換另一種燈泡則需要進行很大的改動,那麼如何解決這個問題呢?就想我們組裝電腦一樣,主板、CPU、硬盤等等,它們之間都互相遵循了同樣的接口。不管是AMD的CPU、還是Inter的CPU,它們之間都用一種同樣的公開接口,將來替換CPU就會很方便,其他硬件同樣。
那麼我們能不能將我們燈泡也想電腦硬件一樣,使用同一的接口進行操作呢?當然沒問題。分析一下既然燈泡都是發光,那麼我們就可以將燈泡統一一種協議或者叫約定,即所有燈泡將來都以一種接口呈現。代碼如下:
- //燈泡的約定
- public interface IBulb
- {
- //統一的發光接口
- public void Luminescence();
- }
有了約定(接口),那麼所有的燈泡都遵循這個約定,我們以後如果需要更換燈泡或者引進新品種燈泡,只需要跟替換電腦配件那樣,把舊的拔下來新的插上去,代碼如下:
- //燈泡
- public class Bulb : IBulb//實現了燈泡的約定、標準
- {
- //發光
- public void Luminescence()
- {
- //燈泡發光的實現
- }
- }
- //節能燈泡
- public class FrugalBulb : IBulb //實現了燈泡的約定、標準
- {
- //節能發光
- public void Luminescence()
- {
- //節能燈泡發光的實現
- }
- }
這個時候我們在來替換一次燈泡看看,模擬代碼如下:
- static void Main(string[] args)
- {
- //是否感應到人 默認是
- bool isOpen = true;
- //普通燈泡
- Bulb bulb = new Bulb();
- //節能燈泡
- FrugalBulb fBulb = new FrugalBulb();
- //感應是否生效
- if (isOpen)//默認生效
- {
- //感應器控制燈泡發光
- Induction induction = new Induction();
- //普通燈泡發光
- induction.Open(bulb);
- //節能燈泡發光
- induction.Open(fBulb);
- }
- }
- /// <summary>
- /// 感應器
- /// </summary>
- public class Induction
- {
- //打開終端(燈泡)
- public void Open(IBulb bulb)
- {
- //發光
- bulb.Luminescence();
- }
- }
- //燈泡的約定
- public interface IBulb
- {
- //統一的發光接口
- public void Luminescence();
- }
- //燈泡
- public class Bulb : IBulb//實現了燈泡的約定、標準
- {
- //發光
- public void Luminescence()
- {
- //燈泡發光的實現
- }
- }
- //節能燈泡
- public class FrugalBulb : IBulb //實現了燈泡的約定、標準
- {
- //節能發光
- public void Luminescence()
- {
- //節能燈泡發光的實現
- }
- }
這個時候還有個問題,如果我們將來需要支持彩色燈泡怎麼辦?我們是不是要增加一個彩色燈泡的類實現燈泡的約定接口,還需要在調用方寫入調用的代碼。這個時候我們就可以使用工廠類維護這些燈泡,例如:我的燈泡工廠,目前可以製造,普通燈泡,節能燈泡,彩色燈泡。以後我們需要其中哪種燈泡,就通知工廠來供貨。代碼如下:
- public class MyBulbFactory
- {
- public static IBulb GetBulb(string bulbName)
- {
- IBulb bulb = null;
- //告訴我你要什麼燈泡,我製造相應的燈泡給你
- switch (bulbName)
- {
- case "bulb":
- bulb = new Bulb();
- break;
- case "frugalbulb":
- bulb = new FrugalBulb();
- break;
- case "colorbulb":
- bulb = new ColorBulb();
- break;
- }
- return bulb;
- }
- }
- /// <summary>
- /// 感應器
- /// </summary>
- public class Induction
- {
- //打開終端(燈泡)
- public void Open(IBulb bulb)
- {
- //發光
- bulb.Luminescence();
- }
- }
- //燈泡的約定
- public interface IBulb
- {
- //統一的發光接口
- public void Luminescence();
- }
- //燈泡
- public class Bulb : IBulb//實現了燈泡的約定、標準
- {
- //發光
- public void Luminescence()
- {
- //燈泡發光的實現
- }
- }
- //節能燈泡
- public class FrugalBulb : IBulb //實現了燈泡的約定、標準
- {
- //節能發光
- public void Luminescence()
- {
- //節能燈泡發光的實現
- }
- }
- //彩色燈泡
- public class ColorBulb : IBulb
- {
- //彩色發光
- public void Luminescence()
- {
- //彩色燈泡發光的實現
- }
- }
這樣將來我們需要什麼,只需要告訴工廠我要什麼,工廠就會給我們提供了統一接口的燈泡,提供我們使用。 主函數調用代碼如下:
- static void Main(string[] args)
- {
- //是否感應到人 默認是
- bool isOpen = true;
- //感應是否生效
- if (isOpen)//默認生效
- {
- //感應器控制燈泡發光
- Induction induction = new Induction();
- //我需要普通燈泡
- IBulb bulb = MyBulbFactory.GetBulb("bulb");
- //普通燈泡發光
- induction.Open(bulb);
- //我需要節能燈泡
- IBulb fBulb = MyBulbFactory.GetBulb("frugalbulb");
- //節能燈泡發光
- induction.Open(fBulb);
- //我需要彩色燈泡
- IBulb cBulb = MyBulbFactory.GetBulb("colorbulb");
- induction.Open(cBulb);
- }
- }
使用工廠模式,可以有效的減少更換同類部件的成本。
3、抽象類與接口的個人理解
很多人都很迷惑什麼時候應該使用接口,什麼時候應該使用抽象類呢?
在.NET企業級架構設計一書中,作者對這方面的解釋爲:“在那些不支持多繼承的面嚮對象語言(例如,java、C#、和 Visual Basic.NET)中,我們一般傾向於使用接口,因爲這樣其基類仍有挑選的餘地,若支持多繼承,則是使用上的偏好了。”
融合了上面的概念後,我總結的是,當類型之間存在集成關係時,我們使用抽象類,例如一個抽象類人類,那麼男人和女人都是人類,他們之間存在着這種派生關係,當類型之間需要遵循一系列約定或者規則時使用接口,例如男人和女人都要學習,工作等等。
也就是說,類型天生的部分封裝成抽象類,後天添加的規則方法,使用接口,代碼實現如下【個人理解僅供參考】:
- //學習的約定 規則 行爲
- public interface ILearn
- {
- public void Learn();
- }
- //人類是個抽象的類型
- public abstract class Person
- {
- //活動
- public virtual void Activity();
- }
- //男人類
- public class Man : Person,ILearn
- {
- //人類天生的行爲
- public override void Activity()
- {
- }
- //後天的行爲
- public void Learn()
- {
- //學習追女人
- }
- }
- //女人類
- public class Woman : Person,ILearn
- {
- //人類天生的行爲
- public override void Activity()
- {
- }
- //後天的行爲
- public void Learn()
- {
- //學習被男人追
- }
- }