• <tfoot id="ukgsw"><input id="ukgsw"></input></tfoot>
    
    • 久久精品精选,精品九九视频,www久久只有这里有精品,亚洲熟女乱色综合一区
      分享

      從容自若的CTO

       ljjzlm 2006-08-04

      從容自若的CTO

      Filed under:— bruce zhang @ 1:31 pm

      讓我們假設這樣一個場景:一年以前,Media公司開發出一套通過電腦接收廣播的Radio仿真軟件產品。(有這樣的產品嗎,能真正接收廣播的軟件?我表示懷疑)這個產品早已投入市場,客戶已經在使用了。后來,Media公司將開發重心轉移到數字媒體上。于是他們投入了大量的人力物力,最后開發出了完美的媒體播放器軟件。這個播放器支持大多數媒體文件,包括音頻媒體和視頻媒體。該產品取得了成功,也得到了用戶的好評。

      不過,現實生活中總有些刁鉆的客戶,比如說wayfarer,就是鄙人了,素愛懷舊。在使用媒體播放器的時候,想起了在初中的時候就使用的收錄機。磁帶、廣播,一機兩用,真是令人懷念。于是我向Media公司提出了建議,希望能在媒體播放器中增加收音的功能。Media的CEO對這個似乎有些嗤之以鼻。可是像wayfarer這樣的用戶越來越多,呼聲也越來越高。為了產品的市場,為了公司的前景,這位CEO不得不慎重考慮這個需求了。當首席執行官就是好,趕緊把這個燙手山芋拋給了CTO。

      卻看這位CTO仍然是從容不迫,臉上掛滿自信的微笑。CEO不解,問他何故如此從容?CTO淡然一笑,吐出一字真言:“Adapter”。

      呵呵,笑話了。設計模式可不是什么Bible,也非神奇的魔咒。不過對于以上場景,使用Adapter卻是最佳的應用!且請聽我慢慢道來。

      已有產品:MediaPlayer、RadioPlayer;
      分析:MediaPlayer是面向客戶的外觀,即表示層,它調用了對應的業務層,該層實現了IMedia接口。同理RadioPlayer也是面向客戶的外觀,它調用的業務層,是收聽廣播的業務,并實現了IRadio接口。
      目的:將RadioPlayer的業務添加到MediaPlayer的外觀中。原有的RadioPlayer不再使用。

      既然與MediaPlayer、RadioPlayer的業務有關,所以我們有必要分析其各自的業務結構。MediaPlayer業務層結構:

      為了簡化,我這里將所有的方法都放在一個接口IMedia里(這個設計還有很多重構的空間,我會在后續文章中繼續關注)。在本文的結構中,視頻媒體和音頻媒體的方法是相同的,本來我可以令各媒體文件繼承同一個抽象類Media。但現實情況顯然不是這樣,所以我仍然保留這個系列文章中原有的結構。以下是每個方法的說明:
          Play():播放媒體文件;
          Stop():停止播放;
          Pause():暫停播放;
          OpenFile():打開媒體文件;
          CloseFile():關閉媒體文件;
          Forward():前進播放文件;
          Back():后退播放文件;

      OK,我們再來看看RadioPlayer的業務層結構:


      RadioPlayer的業務均抽象為IRadio接口。并由抽象類Radio實現該接口。FM為調頻收音,SW為短波收音。另外還有其他的,例如中波等,就不在詳細列出。各方法的功能說明如下:
          Receive():接收廣播;
          Stop():停止接收廣播;
          TurnOn():打開收音;
          TurnOff():關閉收音;
          ChangeChannel(bool direction):切換頻率。參數direction為true時,則往上;否則往下。當然也可以使用枚舉類型。

      媒體播放器的業務由一個統一的Client類進行處理,它包括一系列的靜態方法以實現對原有媒體類型的調用:
      public class Client
      {
       public static void Play(IMedia media)
       {
        media.Play();
       }

       public static void OpenFile(IMedia media)
       {
        media.OpenFile();
       }
       
       //……其他方法略;
      }
      MediaPlayer播放器本身,其外觀則是一個WinForm應用程序,該應用程序將調用Client的相關靜態方法。如:
      Client.Play(new MP3());

      現在看看我們需要實現的。我需要將RadioPlayer的業務,即抽象為IRadio接口的對象,放到MediaPlayer中。糟糕的是,Client的各個方法傳遞的參數類型,為IMedia接口。怎么才能將實現IRadio接口的對象傳遞到Client的方法中呢?對了,這就是適配,就是為IRadio對象適配成符合IMedia接口行為的過程。打一個不好聽的比方,就好比一只狼,要讓自己鉆進羊群里,而不被發現,就需要找一張羊皮來披上。俗語云:“披著羊皮的狼”是也。不過,我們要注意的是,狼雖然不是羊,但有著和羊相似的屬性。它和羊體形相似,照樣能跑,能吃,只是吃的不是草,而是肉而已。你總不能為一張桌子披上羊皮,去裝羊吧。而文中的IMedia類型和IRadio類型,還是有很多相似之處的。

      現在,我們就為IRadio接口進行適當的包裝。由于這是兩個接口進行匹配的過程,所以我們通常名之為“適配”,而非“包裹”。那么它們之間有相似性嗎?有!
      IMedia    IRadio
      Play()    Receive()
      Stop()    Stop()
      OpenFile()   TurnOn()
      CloseFile()   TurnOff()
      Forward()   ChangeChannel(true)
      Back()    ChangeChannel(false)

      當然現實情況并非總是那么完美。可能IMedia的方法中,IRadio可能并不需要。沒關系,我們只提供該方法就可以了,方法的實現可以為空,如Pause()方法。也有可能IRadio的一些方法,IMedia并沒有,此時的Adaptor模式,就將被適配對象的接口變寬了,也就是說引入了新的行為,這就類似于我系列文章之二所描述的。

      不管現實的某些情況是多么的不如意,但至少通過引入Adapter模式,我們就不需要改變原有的IMedia和IRadio的相關對象與業務了。要修改的,僅僅是客戶端,以及增加一個新的Adapter結構而已。

      分析結束,開始動手術吧。先看類的Adapter模式:


      類圖好像很復雜,不過請大家主要關注橙色的兩個類FMAdapter和SWAdapter。FMAdapter類是FM類型的Adapter,它繼承了FM類,并實現了IMedia接口。通過這種方式,原有的FM類型的行為,就被適配為符合IMedia類型的新類型。代碼如下:
      public class FMAdapter:FM,IMedia
      {
       public void Play()
       {
        this.Receive();
       }
       public void Forward()
       {
        this.ChangeChannel(true);
       }
       public void Pause(){}//Radio類型沒有該行為,令其為空,或引入異常機制;
       //其他方法略
       …… 
      }
      SWAdapter的實現方式完全相同,就不贅述。

      由于新的Adapter類均實現了IMedia接口,因此,該類型的對象可以安全正確地作為Client靜態方法的參數對象傳入。從外部行為的表現來看,沒有區別。如:
      Client.Play(new FMAdapter());
      它調用了FMAdapter的Play方法,而其內部,實質上調用的是FM的Receiver()方法。

      再看對象的Adapter模式,就更簡單了。

      只需要一個Adapter類RadioAdapter,然后實現IMedia接口。沒有繼承關系了,而是聚合了Radio對象。注意,這里聚合的是抽象類對象Radio,而不是具體的FM或SW。
      public class RadioAdapter:IMedia
      {
       private Radio _radio; 
       public RadioAdapter(Radio radio)
       {
        this._radio = radio;
       }
       public void Play()
       {
        _radio.Receive();
       }
       public void Forward()
       {
        _radio.ChangeChannel(true);
       }
       public void Pause(){}//Radio類型沒有該行為,另其為空,或引入異常機制;
       //其他方法略
       …… 
      }
      調用Client的靜態方法:
      Client.Play(new RadioAdapter(new FM()));

      通過引入Adapter模式,我們在不改變原有IMedia和IRadio的情況下,順利地將IRadio類型適配成了IMedia類型。此時,我們只需要在MediaPlayer的客戶端調用中加入原來RadioPlayer的業務即可,基本保證了原有系統的穩定性。

      上述實例,才真正體現了Adapter的價值(請大家一定注意區分本文實例需求,與系列之二實例需求的區別)。因此,我們可以得到兩個結論:
      1、通過Adapter模式,為適配對象引入以前不具備的行為;此時建議使用類的Adapter模式。理由請參考:系列文章之二與之三;
      2、將一個固有對象適配為另一種接口對象;這是Adapter模式最重要的功能。使用類的Adapter模式與對象的Adapter模式均可,但感覺使用對象的Adapter模式更簡單。

      怎么樣,夠簡單吧?難怪我們的CTO如此從容,因為他已經找到了終南捷徑!

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發現有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發表

        請遵守用戶 評論公約

        類似文章 更多

        主站蜘蛛池模板: 国产一区二区高清不卡| √天堂中文www官网在线| AV无码中文字幕不卡一二三区| 日韩深夜免费在线观看| 人妻中出无码中字在线| 上课忘穿内裤被老师摸到高潮| 国产精品亚洲二区在线播放| 日日橹狠狠爱欧美视频| 国产亚洲精AA在线观看SEE| 国产AV老师黑色丝袜美腿 | 婷婷色香五月综合缴缴情香蕉| 亚洲 欧洲 无码 在线观看| 无码囯产精品一区二区免费| 无码熟妇人妻AV影音先锋| 日韩av片无码一区二区不卡| 成人欧美一区二区三区的电影| 一本一道av中文字幕无码| 99久久国产综合精品女图图等你| 麻豆一区二区中文字幕| 无码精品人妻一区二区三区中| 成人啪精品视频网站午夜 | 日本边添边摸边做边爱的视频| 午夜福利在线观看6080| 国产午夜视频在线观看| 久久亚洲AV成人网站玖玖| 精品无码成人片一区二区| 久久综合综合久久综合| 亚洲欧洲日产国无高清码图片 | 日本理伦片午夜理伦片| 97久久超碰亚洲视觉盛宴| 强奷漂亮人妻系列老师| 无码国产精品一区二区免费模式| 人妻系列无码专区免费| 久久精品国产亚洲av麻豆软件| 精品国产一区二区三区2021 | 强行无套内大学生初次| 欧洲亚洲精品免费二区| 欧美日韩中文国产一区发布| 人妻精品久久无码专区精东影业| 精品中文人妻在线不卡| 国产综合AV一区二区三区无码|