重新學.Net[八]——CLR的物件導向實現

來源:互聯網
上載者:User

懶了好幾天,盡玩去了。恩,趕在年前,把想寫的再寫一點^_^。

.Net目的之一是建立一個物件導向的編程平台。CLR當然需要支援物件導向的各個特徵,確切一些,CLR基本可以視為一個完全物件導向的平台(回憶一下之前說的CTS)。CLR的物件導向有一些自己的特點和實現手段,下面會分點寫一點,很零星不系統,算是一個筆記吧。

封裝:
CLR對封裝的支援沒有什麼特殊的。仍然是public,private,protected(在這裡使用C#的文法而不是CLR的文法,方便大家理解,下同)幾種主要許可權,比較特殊的有Internal,將許可權擴大到了程式集層級,我很少有用到,感覺破壞美好的感覺^_^。比較值得一說的是利用介面來巧妙實作類別似於友元的功能,有興趣的可以查一下C#實現記事本模式的方法。

抽象:
在CLR中(下面還是用C#文法),支援虛基類(abstract class,無法執行個體化,僅能用於做基類)和介面(interface)。在設計模式中有這樣一個基本原則:面向介面編程。我個人覺得這裡說的介面影射到C#中,不僅僅指interface,而應該指所有的抽象手段,包括abstract class 和interface。而在很多情況下,我們應該優先使用虛基類而不是介面。因為abstract class具有更好的可修改性。比如你提供了一個稱為superman的abstract class和interface。當初它只有fly一個方法。後來我想為他添加一個walk的方法(超人也是人嘛,也不能天天飛啊)。這時候如果你用abstract class實現,只需要添加一個含預設實現的walk即可,而如果是interface實現的,不僅要改介面,還需要修改所有實現了該介面的類型(當然有時候這樣還更好,很安全)。一個很有名的經驗性原則是Is-a和Can-do原則。如果子類是基類的一部分用abstract class,如果基類只是子類擁有的一項功能,請用interface。相比之下,interface的設計要求更高一些,你一定要確定它不會被更改,否則會很痛苦。
回到設計模式中的面向介面編程原則,確實是金玉良言,但也不可強求。有時候確實不需要抽象了,就不必抽象了。在實踐中還有一個很有效原則必須遵守就是儘可能用最抽象的介面進行通訊。考慮下面兩種函數實現:
public IList getList();
public ArrayList getList();
如果,前面一個函數能滿足你的需求,就千萬別用第二個。更高的抽象意味著更低的通訊成本和更高的變化支援。比如有一天我討厭用預設的ArrayList實現我的功能了,我自己實現IList。那麼所有用第二個函數的函數都需要修改,這是一個很恐怖的事情,絕對應該盡量避免。

多態:
在CLR層面,對多態的支援十分的全面。可以支援不同的參數各數,不同參數類型,不同傳回值的函數多態。但是,在語言成面,比如C#。還只是能支援不同參數類型或數量的重載。
在實際應用中,我們應該盡量用多態了代替使用預設參數,同時把函數的具體實現放在有最長參數列的函數中,其他函數調用該函數即可。比如:
public void TheMethod(int a,int b,string s){//實現}
public void TheMethod(int a,int b){TheMethod(a,b,"");}
這也可以被用於檢查你是否正確使用多態。比如你有一個TheMethod(int a)根本無法很好的調用TheMethod(int a,int b,string s)來作為其實現,你就應該考慮一下你這個函數的命名了,應該把它剔除出你的多態體系,另立門派。

繼承:
繼承是物件導向中最有效也是最麻煩的手段之一。用好繼承實在是不容易的一件事情。CLR不支援多繼承,你可以通過繼承介面來實現多繼承的需求。這降低了繼承的複雜性。設計模式中另一個很重要的原則是優先使用組合而不是繼承,同樣一條不容置疑的金玉良言。一定要學會正確使用繼承,這十分重要。
繼承中很重要的一項內容就是函數的重寫。CLR有其自己的一套虛函數實現機制,它利用中繼資料對虛函數進行動態解析,不論你子類是否構造完成,它都具有調用到目前最深的繼承體系中類的函數的功能。如果你熟悉C++,請一定要分清楚,這與C++中有很大的不同。(C++是用虛表來實現,動態構造。而CLR中用中繼資料標識,動態解析)想說清楚其中的不同不是一件很容易的事情。你可以嘗試實現寫下如下的代碼:
    public abstract class Base
    {
        public Base()
        {
            Method();
        }

        public abstract void Method();
    }

    public class Derived : Base
    {
        private int value;
        public Derived()
        {
            value = 1;
        }

        public override void Method()
        {
            if (value == 1)
            {
                Console.WriteLine("OK");
            }
            else
            {
                Console.WriteLine("Wrong");
            }
        }
    }
然後執行個體化一個Derived對象,看看是否能夠通過編譯,運行結果是否與預期相符。還可以移植到C++中實現一下,也許你會有出乎意料的發現,對此機制有更好的瞭解。
瞭解這個情況,有助於你在建構函式中正確使用虛函數,也許下次你不會寫出類似於上面那段代碼的代碼了。
與函數的重載需要一起說明的是函數的隱藏。如果基類中沒指名函數是虛函數,子類中出現同名函數就會將基類中的同名函數隱藏。你可以用new關鍵字(C#中)放置在函數前,明確地告訴編譯器,沒錯,我就是想隱藏它。要特別注意的就是類似於下面的代碼也會被視為隱藏:
virtual void TheMethod() //基類中
void TheMethod() //子類中
你需要在子類函數前添加overide關鍵字告訴編譯器我是想重寫而不是隱藏。

其他:
在OO編程中還有很多需要注意的東西。比如預設建構函式,傳值和傳址,靜態類等等。上面的只是一個簡單的摘要,要瞭解更多細節需要多看書,多實踐,多思考,希望大家共同提高共同進步。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.