今天回家一開燈感覺客廳的燈暗了許多,抬頭一看原來是燈泡快壞了,想想這個燈泡也是老式的不如換個新的節能燈泡算了。於是跑到小區對面的德爾泰市場買了同樣接口的節能燈泡,這樣光線又好又可以為自己節約電費,回來后迅速拿起凳子,換了新燈泡感覺亮堂了許多。高興之余就想用代碼去模擬一下這個場景。
1、案例設想
設想如果我們編寫一個程序通過聲控感應設備去控制燈光的顯示,那么如何實現呢?我想首先第一步就是需要設計當感應設備捕獲到人的時候如何處理,第二部就是在處理內部控制燈泡發光,例如聲控設備感應到人的時候,控制我們平時的普通燈泡去發光。通過面向對象封裝模擬的代碼如下:
{
// 是否感應到人 默認是
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()
{
// 節能燈泡發光的實現
}
}
那么這個時候我的普通燈泡壞了,為了考慮成本,決定將普通的燈泡替換成節能燈泡,那么就會出現一個問題,當普通燈泡的插孔與節能燈泡的插孔不同時?我們需要將燈泡的插孔也替換掉,並且感應器也要增加對應節能燈泡的調用,這樣就大大的增加了替換的成本,不好的替換方式用代碼模擬實現如下:
{
// 是否感應到人 默認是
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
{
// 統一的發光接口
void Luminescence();
}
有了約定(接口),那么所有的燈泡都遵循這個約定,我們以后如果需要更換燈泡或者引進新品種燈泡,只需要跟替換電腦配件那樣,把舊的拔下來新的插上去,代碼如下:
public class Bulb : IBulb // 實現了燈泡的約定、標准
{
// 發光
public void Luminescence()
{
// 燈泡發光的實現
}
}
// 節能燈泡
public class FrugalBulb : IBulb // 實現了燈泡的約定、標准
{
// 節能發光
public void Luminescence()
{
// 節能燈泡發光的實現
}
}
這個時候我們在來替換一次燈泡看看,模擬代碼如下:
{
// 是否感應到人 默認是
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
{
// 統一的發光接口
void Luminescence();
}
// 燈泡
public class Bulb : IBulb // 實現了燈泡的約定、標准 {
// 發光
public void Luminescence()
{
// 燈泡發光的實現
}
}
// 節能燈泡
public class FrugalBulb : IBulb // 實現了燈泡的約定、標准
{
// 節能發光
public void Luminescence()
{
// 節能燈泡發光的實現
}
}
這個時候還有個問題,如果我們將來需要支持彩色燈泡怎么辦?我們是不是要增加一個彩色燈泡的類實現燈泡的約定接口,還需要在調用方寫入調用的代碼。這個時候我們就可以使用工廠類維護這些燈泡,例如:我的燈泡工廠,目前可以制造,普通燈泡,節能燈泡,彩色燈泡。以后我們需要其中哪種燈泡,就通知工廠來供貨。代碼如下:
{
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
{
// 統一的發光接口
void Luminescence();
}
// 燈泡
public class Bulb : IBulb // 實現了燈泡的約定、標准 {
// 發光
public void Luminescence()
{
// 燈泡發光的實現
}
}
// 節能燈泡
public class FrugalBulb : IBulb // 實現了燈泡的約定、標准
{
// 節能發光
public void Luminescence()
{
// 節能燈泡發光的實現
}
}
// 彩色燈泡
public class ColorBulb : IBulb
{
// 彩色發光
public void Luminescence()
{
// 彩色燈泡發光的實現
}
}
這樣將來我們需要什么,只需要告訴工廠我要什么,工廠就會給我們提供了統一接口的燈泡,提供我們使用。 主函數調用代碼如下:
// 是否感應到人 默認是
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
{
void Learn();
}
// 人類是個抽象的類型
public abstract class Person
{
// 活動
public abstract 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()
{
// 學習被男人追
}
}