這次我們來關注條款20:Distinguish Between Implementing Interfaces and Overriding Virtual Functions。
條款20的解釋中,作者的目標是實現一個介面,並在衍生類別中改變它的實現,即:
interface IMsg
{
void Message();
}
// public class MyBaseClass : IMsg
//
// public class MyDerivedClass : MyBaseClass
//
MyBaseClass b = new MyBaseClass();
b.Message()
MyDerivedClass d = new MyDerivedClass();
d.Message()
//output:
//MyBaseClass
//MyDerivedClass
作者提到,要實現它,有兩種選擇,一是在衍生類別中使用new關鍵字重新實現介面;二是在基類中public virtual void Message(),並在衍生類別中override。並且建議override。但是這樣做很好嗎?
不好。
先說new掉基類public方法有什麼弊端。一般情況下,介面定義了行為,抽象類別的公用方法定義了這些行為的規範。比方說完成一個功能A,中間有若干步驟(k1,k2,k3...),完成整個功能,必須按照k1,k2,k3的順序執行。所謂的“OOD”則一般把k1,k2,k3定義成protected virtual,允許衍生類別override。現在,如果衍生類別new掉了A會有什麼後果呢?能保證這些中間步驟的順序執行?
OK,現在各位發現基類中public virtual方法也有同樣的問題。所以,書中建議的方法都不好。
那麼怎麼做才happy一些呢?
基類使用public方法實現介面,並提供一個protected virtual的internal方法完成真正的操作,衍生類別只override這些方法。
最後做個總結:
1、衍生類別儘可能不new掉基類的public方法。如果出現這樣的需求,那一定是基類的設計有問題。
2、基類所有的virtual和abstract方法應該只是protected。
3、(加上上篇提到的結論)儘可能使用抽象類別,而不是直接實現介面。(這個可以仔細看看msdn,仔細看看.net framework的實現,微軟就是建議這麼做)
4、(補上篇結論中提到的一點)方法參數,泛型中的T都應該限制最小化。