官术网_书友最值得收藏!

1.4 多態(tài)的藝術(shù)

本節(jié)將介紹以下內(nèi)容:

·什么是多態(tài)?

·動(dòng)態(tài)綁定

·品味多態(tài)和面向?qū)ο?/p>

1.4.1 引言

翻開大部頭的《韋氏大詞典》,關(guān)于多態(tài)(Polymorphisn)的定義為:可以呈現(xiàn)不同形式的能力或狀態(tài)。這一術(shù)語來源于生物系統(tǒng),意指同族生物具有的相同特征。而在.NET中,多態(tài)指同一操作作用于不同的實(shí)例,產(chǎn)生不同運(yùn)行結(jié)果的機(jī)制。繼承、封裝和多態(tài)構(gòu)成面向?qū)ο笕兀删土嗣嫦驅(qū)ο缶幊棠J降幕A(chǔ)技術(shù)機(jī)制。

在本節(jié),我們以入情入理的小故事為線索,來展開一次關(guān)于多態(tài)的循序漸進(jìn)之旅,在故事的情節(jié)中思考多態(tài)和面向?qū)ο蟮乃囆g(shù)品質(zhì)。

1.4.2 問題的拋出

故事開始。

小王的爺爺,開始著迷于電腦這個(gè)新鮮玩意兒了,但是老人家面對(duì)陌生的屏幕卻總是摸不著頭腦,各種各樣的文件和資料眼花繚亂,老人家卻不知道如何打開,這可急壞了身為光榮程序員的小王。為了讓爺爺享受高科技帶來的便捷與震撼,小王決定自己開發(fā)一個(gè)萬能程序,用來一鍵式打開常見的計(jì)算機(jī)資料,例如文檔、圖片和影音文件等,只需安裝一個(gè)程序就可以免了其他應(yīng)用文件的管理,并且使用方便,就暫且稱之為萬能加載器(FileLoader)吧。

既然是個(gè)獨(dú)立的應(yīng)用系統(tǒng),小王就分析了萬能加載器應(yīng)有的幾個(gè)功能點(diǎn),小結(jié)如下:

·自動(dòng)加載各種資料,一站式搜索系統(tǒng)常見資料。

·能夠打開常見文檔類資料,例如txt文件、Word文件、PDF文件、Visio文件等。

·能夠打開常見圖片資料,例如jpg格式文件、gif格式文件、png格式文件等。

·能夠打開常見音頻資料和視頻資料,例如avi文件、mp3文件等。

·支持簡單可用的類型擴(kuò)展接口,易于實(shí)現(xiàn)更多文件類型的加載。

這可真是一個(gè)不小的挑戰(zhàn),小王決定利用業(yè)余時(shí)間逐步地來實(shí)現(xiàn)這一偉大的構(gòu)想,就當(dāng)成是送給爺爺60歲的壽禮。有了一個(gè)令人興奮的念頭,小王怎么都睡不著,半夜按捺不住爬起來,構(gòu)思了一個(gè)基本的系統(tǒng)流程框架,如圖1-11所示。

圖1-11 萬能加載器系統(tǒng)框架圖

1.4.3 最初的實(shí)現(xiàn)

說干就干,小王按照構(gòu)思的系統(tǒng)框架,首先構(gòu)思了可能打開的最常用的文件,并將其設(shè)計(jì)為一個(gè)枚舉,這樣就可以統(tǒng)一來管理文件的類型了,實(shí)現(xiàn)如下:

//可支持文件類型,以文件擴(kuò)展名劃分
enum FileType
{
   doc, //Word文檔
   pdf, //PDF文檔
   txt, //文本文檔
   ppt, //Powerpoint文檔
   jpg, //jpg格式圖片
   gif, //gif格式圖片
   mp3, //mp3音頻文件
   avi  //avi視頻文件
}

看著這個(gè)初步設(shè)想的文件類型枚舉,小王暗暗覺得真不少,如果再增加一些常用的文件類型,這個(gè)枚舉還真是氣魄不小呀。

有了要支持的文件類型,小王首先想到的就是實(shí)現(xiàn)一個(gè)文件類,來代表不同類型的文件資料,具體如下:

class Files
{
   private FileType fileType;
   public FileType FileType
   {
      get { return fileType; }
   }
}

接著小王按照既定思路構(gòu)建了一個(gè)打開文件的管理類,為每種文件實(shí)現(xiàn)其具體的打開方式,例如:

class FileManager
{
   //打開Word文檔
   public void OpenDocFile()
   {
      Console.WriteLine("Alibaba, Open the Word file.");
   }
   //打開PDF文檔
   public void OpenPdfFile()
   {
      Console.WriteLine("Alibaba, Open the PDF File.");
   }
   //打開Jpg文檔
   public void OpenJpgFile()
   {
      Console.WriteLine("Alibaba, Open the Jpg File.");
   }
   //打開MP3文檔
   public void OpenMp3File()
   {
      Console.WriteLine("Alibaba, Open the MP3 File.");
   }
}

哎呀,這個(gè)長長的單子還在繼續(xù)往下寫:OpenJpgFile、OpenGifFile、OpenMp3File、OpenAviFile……不知到什么時(shí)候。

上一步著實(shí)讓小王步履維艱,下一步的實(shí)現(xiàn)更讓小王瀕臨崩潰了,在系統(tǒng)調(diào)用端,小王實(shí)現(xiàn)的文件加載器是被這樣實(shí)現(xiàn)的:

class FileClient
{
   public static void Main()
   {
      //首先啟動(dòng)文件管理器
      FileManager fm = new FileManager();
      //看到一堆一堆的電腦資料
      IList<Files> files = new List<Files>();
      //當(dāng)前的萬能加載器該如何完成工作呢?
      foreach (Files file in files)
      {
         switch(file.FileType)
         {
            case FileType.doc:
               fm.OpenDocFile();
               break;
            case FileType.pdf:
               fm.OpenPdfFile();
               break;
            case FileType.jpg:
               fm.OpenJpgFile();
               break;
            case FileType.mp3:
               fm.OpenMp3File();
               break;
            //……部分省略……
         }
      }
   }
}

完成了文件打開的調(diào)用端,一切都好像上了軌道,小王的萬能文檔器也有了基本的架子,剩下再根據(jù)實(shí)際需求做些調(diào)整即可。小王興沖沖地將自己的作品拿給爺爺試手,卻發(fā)現(xiàn)爺爺正在想打開一段rm格式的京劇聽聽。但是小王的系統(tǒng)還沒有支持這一文件格式,沒辦法只好回去繼續(xù)修改了。

等到要添加支持新類型的時(shí)候,拿著半成品的小王,突然發(fā)現(xiàn)自己的系統(tǒng)好像很難再插進(jìn)一腳,除了添加新的文件支持類型,修改打開文件操作代碼,還得在管理類中添加新的支持代碼,最后在客戶端還要修改相應(yīng)的操作。小王發(fā)現(xiàn)添加新的文件類型,好像把原來的系統(tǒng)整個(gè)做了一次大裝修,那么下次爺爺那里有了新需求呢,號(hào)稱萬能加載器的作品,應(yīng)該怎么應(yīng)付下一次的需求變化呢?這真是噩夢,氣喘吁吁的小王,忍不住回頭看了看一天的作品,才發(fā)現(xiàn)自己好像掉進(jìn)了深淵,無法回頭。勇于探索的小王經(jīng)過一番深入的分析發(fā)現(xiàn)了當(dāng)前設(shè)計(jì)的幾個(gè)重要問題,主要包括:

·需要深度調(diào)整客戶端,為系統(tǒng)維護(hù)帶來麻煩,況且我們應(yīng)該盡量保持客戶端的相對(duì)穩(wěn)定。

·Word、PDF、MP3等,都是可以實(shí)現(xiàn)的獨(dú)立對(duì)象,整個(gè)系統(tǒng)除了有文檔管理類,幾乎沒有面向?qū)ο蟮挠白樱渴敲嫦蚪Y(jié)構(gòu)和過程的開發(fā)方式。

·在實(shí)現(xiàn)打開文件程序時(shí),小王發(fā)現(xiàn)其實(shí)OpenDocFile方法、OpenPDFFile方法以及OpenTxtFile方法有很多可復(fù)用的代碼,而OpenJpgFile方法和OpenGifFile方法也有很多重復(fù)構(gòu)造的地方。

·由于系統(tǒng)之間沒有分割、沒有規(guī)劃,整個(gè)系統(tǒng)就像一堆亂麻,幾乎不可能完成任何簡單的擴(kuò)展和維護(hù)。

·任何修改都會(huì)將整個(gè)系統(tǒng)洗禮一次,修改遍布全系統(tǒng)的整個(gè)代碼,并且全部重新編譯才行。

·需求變更是結(jié)構(gòu)化設(shè)計(jì)的大敵,無法輕松完成起碼的系統(tǒng)擴(kuò)展和變更,例如在打開這一操作之外,如果實(shí)現(xiàn)刪除、重命名等其他操作,對(duì)當(dāng)前的系統(tǒng)來說將是致命的打擊。在發(fā)生需求多變的今天,必須實(shí)現(xiàn)能夠靈活擴(kuò)展和簡單變更的設(shè)計(jì)構(gòu)思,面向?qū)ο笫庆`活設(shè)計(jì)的有效手段之一。

1.4.4 多態(tài),救命的稻草

看著經(jīng)不起考驗(yàn)的系統(tǒng),經(jīng)過了短期的郁悶和摸索,小王終于找到了阿里巴巴念動(dòng)芝麻之門打開的魔咒,這就是:多態(tài)。

沒錯(cuò)!就是多態(tài),就是面向?qū)ο蟆_@是小王痛定思痛后,發(fā)出的由衷感慨。小王再接再厲,顛覆了原來的構(gòu)思,一個(gè)新的設(shè)計(jì)框架應(yīng)運(yùn)而生,如圖1-12所示。

結(jié)合新的框架,比較之前的蹩腳設(shè)計(jì),小王提出了新系統(tǒng)的新氣象,主要包括以下幾個(gè)修改:

·將Word、PDF、TXT、JPG、AVI等業(yè)務(wù)實(shí)體抽象為對(duì)象,并在每個(gè)相應(yīng)的對(duì)象內(nèi)部來處理本對(duì)象類型的文件打開工作,這樣各個(gè)類型之間的交互操作就被分離出來,這樣很好地體現(xiàn)了職責(zé)單一原則的目標(biāo)。

圖1-12 萬能加載器系統(tǒng)設(shè)計(jì)

·將各個(gè)對(duì)象的屬性和行為相分離,將文件打開這一行為封裝為接口,再由其他類來實(shí)現(xiàn)這一接口,有利于系統(tǒng)的擴(kuò)展同時(shí)減少了類與類的依賴。

·將相似的類抽象出公共基類,在基類中實(shí)現(xiàn)具有共性的特征,并由子類繼承父類的特征,例如Word、PDF、TXT的基類可以抽象為DocLoader;而JPG和GIF的基類可以抽象為ImageLoader,這種實(shí)現(xiàn)體現(xiàn)的是面向?qū)ο蟮拈_放封閉原則:對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。如果有新的類型需要擴(kuò)展,則只需繼承合適的基類成員,實(shí)現(xiàn)新類型的特征代碼即可。

·實(shí)現(xiàn)可柔性擴(kuò)展的接口機(jī)制,能夠更加簡單的實(shí)現(xiàn)增加新的文件類型加載程序,也能夠很好的擴(kuò)展打開文件之外的其他操作,例如刪除、重命名等修改操作。

·實(shí)現(xiàn)在不需要調(diào)整原系統(tǒng),或者很少調(diào)整原系統(tǒng)的情況下,進(jìn)行功能擴(kuò)展和優(yōu)化,甚至是無須編譯的插件式系統(tǒng)。

下面是具體的實(shí)現(xiàn),首先是通用的接口定義:

interface IFileOpen
{
   void Open();
}

接著定義所有文件類型的公共基類,因?yàn)楣驳奈募愂遣豢梢詫?shí)例化的,在此處理為抽象類實(shí)現(xiàn)會(huì)更好,詳細(xì)為:

abstract class Files: IFileOpen
{
   private FileType fileType = FileType.doc;
   public FileType FileType
   {
      get { return fileType; }
   }
   public abstract void Open();
}

基類Files實(shí)現(xiàn)了IFileOpen接口,不過在此仍然定義方法為抽象方法。除了文件打開抽象方法,還可以實(shí)現(xiàn)其他的通用文件處理操作,例如文件刪除Delete、文件重命名ReName和獲取文件路徑等。有了文件類型的公共基類,是時(shí)候?qū)崿F(xiàn)其派生類了。經(jīng)過一定的分析和設(shè)計(jì),小王沒有馬上提供具體的資料類型類,而是對(duì)派生類型做了歸檔,初步實(shí)現(xiàn)文件類型、圖片類型和媒體類型三個(gè)大類,將具體的文件類型進(jìn)一步做了抽象:

abstract class DocFile: Files
{
   public int GetPageCount()
   {
      //計(jì)算文檔頁數(shù)
   }
}
abstract class ImageFile : Files
{
   public void ZoomIn()
   {
      //放大比例
   }
   public void ZoomOut()
   {
      //縮小比例
   }
}

終于是實(shí)現(xiàn)具體資料類的時(shí)候了,在此以Word類型為例來說明具體的實(shí)現(xiàn):

class WORDFile : DocFile
{
   public override void Open()
   {
      Console.WriteLine("Open the WORD file.");
   }
}

其他類型的實(shí)現(xiàn)類似于此,不同之處在于不同的類型有不同Open實(shí)現(xiàn)規(guī)則,以應(yīng)對(duì)不同資料的打開操作。小王根據(jù)架構(gòu)的設(shè)計(jì),同時(shí)提供了一個(gè)資料管理類來進(jìn)行資料的統(tǒng)一管理:

class LoadManager
{
   private IList<Files> files = new List<Files>();
   public IList<Files> Files
   {
      get { return files; }
   }
   public void LoadFiles(Files file)
   {
      files.Add(file);
   }
   //打開所有資料
   public void OpenAllFiles()
   {
      foreach(IFileOpen file in files)
      {
         file.Open();
      }
   }
   //打開單個(gè)資料
   public void OpenFile(IFileOpen file)
   {
      file.Open();
   }
   //獲取文件類型
   public FileType GetFileType(string fileName)
   {
      //根據(jù)指定路徑文件返回文件類型
      FileInfo fi = new FileInfo(fileName);
      return (FileType)Enum.Parse(typeof(FileType), fi.Extension);
   }
}

最后,小王實(shí)現(xiàn)了簡單的客戶端,并根據(jù)所需進(jìn)行文件的加載:

class FileClient
{
   public static void Main()
   {
      //首先啟動(dòng)文件加載器
      LoadManager lm = new LoadManager();
      //添加要處理的文件
      lm.LoadFiles(new WORDFile());
      lm.LoadFiles(new PDFFile());
      lm.LoadFiles(new JPGFile());
      lm.LoadFiles(new AVIFile());
      foreach (Files file in lm.Files)
      {
         if (file is 爺爺選擇的) //偽代碼
         {
            lm.OpenFile(file);
         }
      }
   }
}

當(dāng)然,現(xiàn)在的FileLoader客戶端還有很多要完善的工作要做,例如關(guān)于文件加載的類型,完全可以定義在配置文件中,并通過抽象工廠模式和反射于運(yùn)行期動(dòng)態(tài)獲取,以避免耦合在客戶端。不過基本的文件處理部分已經(jīng)能夠滿足小王的預(yù)期。

1.4.5 隨需而變的業(yè)務(wù)

爺爺機(jī)子上的資料又增加了新的視頻文件MPEG,原來的AVI文件都太大了。可是這回根本就沒有難倒小王的萬能加載器。在電腦前輕松地折騰30分鐘后,萬能加載器就可以適應(yīng)新的需求,圖1-13所示的是修改的框架設(shè)計(jì)。

圖1-13 萬能加載器架構(gòu)設(shè)計(jì)調(diào)整

按照這個(gè)新的設(shè)計(jì),小王對(duì)系統(tǒng)只需做如下的簡單調(diào)整,首先是增加處理MPEG文件的類型MPEGFile,并讓它繼承自MediaFile,實(shí)現(xiàn)具體的Open方法即可。

class MPEGFile : MediaFile
{
   public override void Open()
   {
      Console.WriteLine("Open the MPEG file.");
   }
}

接著就是添加處理新文件的加載操作,如下:

lm.LoadFiles(new MPEGFile());

OK。添加新類型的操作就此完成,在沒有對(duì)原系統(tǒng)進(jìn)行修改的基礎(chǔ)上,只需加入簡單的類型和操作即可完成原來看似復(fù)雜的操作,結(jié)果證明新架構(gòu)經(jīng)得起考驗(yàn),爺爺也為小王豎起了大拇指。事實(shí)證明,只要有更合理的設(shè)計(jì)與架構(gòu),在基于面向?qū)ο蠛?NET框架的基礎(chǔ)上,完全可以實(shí)現(xiàn)類似于插件的可擴(kuò)展系統(tǒng),并且無須編譯即可更新擴(kuò)展。

這一切是如何神奇般地實(shí)現(xiàn)了呢?回顧從設(shè)計(jì)到實(shí)現(xiàn)的各個(gè)環(huán)節(jié),小王深知這都是源于多態(tài)機(jī)制的神奇力量,那么究竟什么是多態(tài),.NET中如何來實(shí)現(xiàn)多態(tài)呢?

1.4.6 多態(tài)的類型、本質(zhì)和規(guī)則

從小王一系列大刀闊斧的改革中,我們不難發(fā)現(xiàn)是多態(tài)、是面向?qū)ο蠹夹g(shù)成就了FileLoader的強(qiáng)大與靈活。回過頭來,結(jié)合FileLoader系統(tǒng)的實(shí)現(xiàn)分析,我們也可以從技術(shù)的角度來進(jìn)一步探討關(guān)于多態(tài)的話題。

1.多態(tài)的分類

多態(tài)有多種分類的方式,Luca Cardelli在《On Understanding Types, Data Abstraction, and Polymorphism》中將多態(tài)分為四類:強(qiáng)制的、重載的、參數(shù)的和包含的。本節(jié)可以理解為包含的多態(tài),從面向?qū)ο蟮慕嵌葋砜矗鶕?jù)其實(shí)現(xiàn)的方式我們可以進(jìn)一步分為基類繼承式多態(tài)和接口實(shí)現(xiàn)式多態(tài)。

(1)基類繼承式多態(tài)

基類繼承多態(tài)的關(guān)鍵是繼承體系的設(shè)計(jì)與實(shí)現(xiàn),在FileLoader系統(tǒng)中File類作為所有資料類型的基類,然后根據(jù)需求進(jìn)行逐層設(shè)計(jì),我們從架構(gòu)設(shè)計(jì)圖中可以清楚地了解繼承體系關(guān)系。在客戶端調(diào)用時(shí),多態(tài)是以這種方式體現(xiàn)的:

Files myFile = new WORDFile();
myFile.Open();

myFile是一個(gè)父類Files變量,保持了指向子類WORDFile實(shí)例的引用,然后調(diào)用一個(gè)虛方法Open,而具體的調(diào)用則決定于運(yùn)行時(shí)而非編譯時(shí)。從設(shè)計(jì)模式角度看,基類繼承式多態(tài)體現(xiàn)了一種IS-A方式,例如WORDFile IS-A Files就體現(xiàn)在這種繼承關(guān)系中。

(2)接口實(shí)現(xiàn)式多態(tài)

多態(tài)并非僅僅體現(xiàn)在基于基類繼承的機(jī)制中,接口的應(yīng)用同樣能體現(xiàn)多態(tài)的特性。區(qū)別于基類的繼承方式,這種多態(tài)通過實(shí)現(xiàn)接口的方法約定形成繼承體系,具有更高的靈活性。從設(shè)計(jì)模式的角度來看,接口實(shí)現(xiàn)式多態(tài)體現(xiàn)了一種CAN-DO關(guān)系。同樣,在萬能加載器的客戶端調(diào)用時(shí),也可以是這樣的實(shí)現(xiàn)方式:

IFileOpen myFile = new WORDFile();
myFile.Open();

當(dāng)然,很多時(shí)候這兩種方式都是混合應(yīng)用的,就像本節(jié)的FileLoader系統(tǒng)的實(shí)現(xiàn)方式。

2.多態(tài)的運(yùn)行機(jī)制

從技術(shù)實(shí)現(xiàn)角度來看,是.NET的動(dòng)態(tài)綁定機(jī)制成就了面向?qū)ο蟮亩鄳B(tài)特性。那么什么是動(dòng)態(tài)綁定,.NET又是如何實(shí)現(xiàn)動(dòng)態(tài)綁定呢?這就是本節(jié)關(guān)于多態(tài)的運(yùn)行機(jī)制所要探討的問題。

動(dòng)態(tài)綁定,又叫晚期綁定,是區(qū)別與靜態(tài)綁定而言的。靜態(tài)綁定在編譯期就可以確定關(guān)聯(lián),一般是以方法重載來實(shí)現(xiàn)的;而動(dòng)態(tài)綁定則在運(yùn)行期通過檢查虛擬方法表來確定動(dòng)態(tài)關(guān)聯(lián)覆寫的方法,一般以繼承和虛方法來實(shí)現(xiàn)。在.NET中,虛方法以virtual關(guān)鍵字來標(biāo)記,在子類中覆寫的虛方法則以override關(guān)鍵字標(biāo)記。從設(shè)計(jì)角度考量,通常將子類中共有的但卻容易變化的特征抽取為虛函數(shù)在父類中定義,而在子類中通過覆寫來重新實(shí)現(xiàn)其操作。

注意

嚴(yán)格來講,.NET中并不存在靜態(tài)綁定。所有的.NET源文件都首先被編譯為IL代碼和元數(shù)據(jù),在方法執(zhí)行時(shí),IL代碼才被JIT編譯器即時(shí)轉(zhuǎn)換為本地CPU指令。JIT編譯發(fā)生于運(yùn)行時(shí),因此也就不存在完全在編譯期建立的關(guān)聯(lián)關(guān)系,靜態(tài)綁定的概念也就無從談起。本文此處僅是參照C++等傳統(tǒng)語言的綁定概念,讀者應(yīng)區(qū)別其本質(zhì)。

關(guān)于.NET通過什么方式來實(shí)現(xiàn)虛函數(shù)的動(dòng)態(tài)綁定機(jī)制,詳細(xì)情況請(qǐng)參閱本章1.2節(jié)“什么是繼承”的詳細(xì)描述。在此,我們提取萬能加載器FileLoader中的部分代碼,來深入分析通過虛方法進(jìn)行動(dòng)態(tài)綁定的一般過程:

abstract class Files: IFileOpen
{
   public abstract void Open();
   public void Delete()
   {
      //實(shí)現(xiàn)對(duì)文件的刪除處理
   }
}
abstract class DocFile: Files
{
   public int GetPageCount()
   {
      //計(jì)算文檔頁數(shù)
   }
}
class WORDFile : DocFile
{
   public override void Open()
   {
      Console.WriteLine("Open the WORD file.");
   }
}

在繼承體系的實(shí)現(xiàn)基礎(chǔ)上,接著是客戶端的實(shí)現(xiàn)部分:

Files myFile = new WORDFile();
myFile.Open();

針對(duì)上述示例,具體的調(diào)用過程,可以小結(jié)為:

編譯器首先檢查myFile的聲明類型為Files,然后查看myFile調(diào)用方法是否被實(shí)現(xiàn)為虛方法。如果不是虛方法,則直接執(zhí)行即可;如果是虛方法,則會(huì)檢查實(shí)現(xiàn)類型WORDFile是否重寫該方法Open,如果重寫則調(diào)用WORDFile類中覆寫的方法,例如本例中就將執(zhí)行WORDFile類中覆寫過的方法;如果沒有重寫,則向上遞歸遍歷其父類,查找是否覆寫該方法,直到找到第一個(gè)覆寫方法調(diào)用才結(jié)束。

3.多態(tài)的規(guī)則和意義

·多態(tài)提供了對(duì)同一類對(duì)象的差異化處理方式,實(shí)現(xiàn)了對(duì)變化和共性的有效封裝和繼承,體現(xiàn)了“一個(gè)接口,多種方法”的思想,使方法抽象機(jī)制成為可能。

·在.NET中,默認(rèn)情況下方法是非虛的,以C#為例必須顯式地通過virtual或者abstract標(biāo)記為虛方法或者抽象方法,以便在子類中覆寫父類方法。

·在面向?qū)ο蟮幕疽刂校鄳B(tài)和繼承、多態(tài)和重載存在緊密的聯(lián)系,正如前文所述多態(tài)的基礎(chǔ)就是建立有效的繼承體系,因此繼承和重載是多態(tài)的實(shí)現(xiàn)基礎(chǔ)。

1.4.7 結(jié)論

在爺爺大壽之際,小王終于完成了送給爺爺?shù)纳斩Y物:萬能加載器。看到爺爺輕松地玩著電腦,小王笑開了花,原來幸福是面向?qū)ο蟮摹?/p>

在本節(jié)中,花了大量的筆墨來詮釋設(shè)計(jì)架構(gòu)和面向?qū)ο螅蚨嗷蛏儆行┬e奪主。然而,深入地了解多態(tài)及其應(yīng)用,正是體現(xiàn)在設(shè)計(jì)模式、軟件架構(gòu)和面向?qū)ο蟮乃枷胫校涣硪环矫妫舱嵌鄳B(tài)、繼承和封裝從技術(shù)角度成就了面向?qū)ο蠛驮O(shè)計(jì)模式,所以深入的理解多態(tài)就離不開大肆渲染以消化設(shè)計(jì),這正是多態(tài)帶來的藝術(shù)之美。

主站蜘蛛池模板: 天祝| 客服| 南宫市| 西乌珠穆沁旗| 大连市| 亳州市| 拉萨市| 嵊州市| 上思县| 沛县| 泾阳县| 温州市| 中牟县| 中江县| 瑞丽市| 来安县| 望谟县| 绵竹市| 奇台县| 涡阳县| 卢湾区| 正阳县| 年辖:市辖区| 新余市| 泰安市| 万荣县| 石景山区| 临夏县| 武鸣县| 金平| 鄯善县| 绵阳市| 宣化县| 宣威市| 新余市| 安康市| 澄迈县| 保德县| 揭东县| 镇赉县| 荃湾区|