敏捷式軟體開發 (Agile Software Development)——開放封閉原則OCP

來源:互聯網
上載者:User

首先,讓我們分析一下背景。什麼是軟體開發過程中最不穩定的因素?——答案是需求!需求在軟體開發過程中時時刻刻都可能發生變化。那麼,如何靈活應對變化是軟體結構設計中最重要也是最困難的一個問題。好的設計帶來了極大了靈活性,不好的設計則充斥著僵化的臭味。這樣,也就引出了本文的主題:【開發封閉原則】。

      下面,就來簡單扼要的介紹一下什麼是【開放封閉原則】。【開發封閉原則】包括兩個特徵:對於擴充是開放的;對於修改是封閉的。對於擴充開放,意味著模組的行為是可擴充的。對於修改封閉,就是說在擴充模組行為的同時不對任何既有代碼或二進位代碼(.jar)進行修改。當然,這裡說的過於絕對。有時為了完成某些任務不得不改動既有代碼。但是,我們的目標是盡量的遵守原則。

      那如何才能做到對擴充開發,對修改封閉呢?關鍵在於抽象!那什麼是抽象呢?

      我個人的理解是:抽象是對事物本質的概念上的理解。物件導向的分析中應該以行為分析為主線。舉一個例子說明:假如從北京到上海,我們可以坐飛機,可以坐火車,可以坐汽車,也可以騎單車。那對於這個問題如何分析呢?這個問題的抽象又是什麼呢?也許可以這樣思考:飛機、火車、汽車和單車在本質上都是交通工具。所以得到這樣的分析結果:交通工具被抽象為父類,飛機、火車、汽車和單車都是其特例化的實現,父類中定義一個抽象方法,可以將人從一個地方運送到另外一個地方,各個子類重新定義運送的方式。這個設計無可厚非!但是,注意了!如果哪天某個人心情不錯,想從北京走到上海了。那他的交通工具又是什麼呢?11路!如果把步行也算成交通工具那就太不符合實際了。所以,物件導向的分析角度,不應該是從事物物理方面的關聯去分析,而應該是從事物的行為方面的管理區分析。對於這個問題,一個人從北京道上海,無論是怎麼到達的,只不過是移動策略不同。

      下面,就給出相應的範例程式碼來說明一下上述問題。

      class Traveller {
     private Car car = new Car();
     public void travel(Address srcAddress,Address destAddress){
          car.move(srcAddress,destAddress);
     }
}

      這是最開始直接使用Car的旅行者,如果想替換成AirPlane怎麼辦?修改代碼,用new AirPlane()代替Car。物件導向的實踐原則指出:面向介面編程,而不面向實現編程。當代碼依賴於具體實現時,就缺失了靈活性,面對新的擴充(也就是新的實現),必須修改既有代碼。

      接著,給出設計靈活的代碼:

      class Traveller {
     private TravelStrategy _strategy;
     public void travel(Address srcAddress,Address destAddress){
          _strategy.move(srcAddress,destAddress);
     }
     public void setTravelStrategy(TravelStrategy strategy){
          _strategy = strategy;
     }
}

public interface TravelStrategy{
     void move(Address srcAddress,Address destAddress);
}

public class CarStrategy implements TravelStrategy{
     public void move(Address srcAddress,Address destAddress){
         ...
     }
}

public class AirPlaneStrategy implements TravelStrategy{
     public void move(Address srcAddress,Address destAddress){
         ...
     }
}

public class WorkStrategy implements TravelStrategy{
     public void move(Address srcAddress,Address destAddress){
         ...
     }
}

      使用這種設計就能靈活的應對設計。比如說:現在需要另外一種從北京到上海的方式——爬。呵呵,也許這種行為不可思議,但它也能達到目的。那如何擴充呢?只需要擴充一個新的TravelStrategy實現即可。這樣,Traveller類不需要修改任何代碼!可以通過調用setter方法來切換移動策略。現在還有一個問題:如何確定執行個體化哪個策略?這裡可以引用工廠,專門負責對象執行個體化。可以將需要使用的策略放在檔案中,這樣改變策略時就不需要修改原始碼了。但當新增策略時,還是需要修改Factory。沒辦法,現實中沒有完全符合原則的情況,我們只能儘力去遵守!

       現在,我們看一下以上代碼中類之間的關係。Traveller類、TravelStrategy介面及其實作類別,Traveller類是TravelStrategy介面的客戶代碼。那Traveller和TravelStrategy的關係與TravelStrategy和它的實作類別指尖的關係哪個更緊密一些呢?答案是前者。這也正是另外一個敏捷原則【依賴倒置原則】。高層代碼不應該依賴低層代碼,低層代碼要依賴於高層代碼。在這裡,說白了的意思就是:一個旅行者要從北京到上海,而旅行團已經給他安排好了去的方法,他本身並不關心怎麼到達,只需要知道有辦法到達就可以了。這裡旅行者和到達方法之間的關係就非常密切了,而具體如何到達那是低層次的問題了。

      上述的問題與實現是實現【開放封閉原則】的一種常用方法——策略模式。還有一種常用的實現方法:模板方法。其實,對於這兩種方法的本質所在也就是物件導向中的組合

與繼承。

       我們已經學會了如何封裝變化,那合適才封裝呢?掌握了這項技能是一件好事,但濫用就出問題了~!因為遵循OCP的代價是昂貴的,建立正確的抽象是要花費時間和精力的,同時那些抽象也增加了軟體設計的複雜性。通常,我們採用這種辦法:只受愚弄一次。也就是說,最初的實現不封裝任何東西。當真正的變化到來了,重構代碼,封裝變化,以避免同類問題再次發生。

       OCP是物件導向設計的核心所在。開發人員應該僅僅對程式中呈現出頻繁變化的那些部分做出抽象。拒絕不成熟的抽象與抽象本身一樣重要。

       最後,在簡單介紹一下物件導向分析的常用方法:

尋找問題域中的各個事物或行為共性
從共性中建立抽象
從共性的變化中建立派生
看共性之間的關係如何

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.