面向對象設計原則之開閉原則


兩截門--一個被水平分割為兩部分的門,這樣每一部分都可以獨立保持開放或封閉

開放-封閉原則(The Open-Closed Principle)

軟件實體(類、模塊、函數)應該是可以擴展的,但是不可以修改的。
如果程序中的一處改動就會產生連鎖反應,導致一系列的相關模塊的改動,那么設計就具有僵化的臭味。如果正確的應用OCP,那么以后再進行同樣的改動時,就只需要添加新的代碼,而不必改動已經正常運行的代碼。

描述

主要兩個特征:

  1. “對於擴展是開放的”
    模塊的行為是可以擴展的,當應用的需求改變時,我們可以對模塊進行擴展,使其具有滿足那些改變的新行為。簡言之,我們可以改變模塊的功能。
  2. “對於更改是封閉的”
    對模塊進行擴展時,不必改動模塊的源代碼。

關鍵是抽象

下圖展示了一個簡單的不遵循OCP的設計。Client類和Server類都是具體類,Client類使用Server類。如果我們希望Client對象使用另外一個不同的服務器對象,那么就必須要把Client類中使用Server類的地方更改為新的服務器類

下圖是根據OCP設計重構的設計

ClientInterface類是一個擁有抽象成員函數的抽象類,Client類使用這個抽象類。如果我們希望Client對象使用一個不同的服務器類,那么只需要沖ClientInterface類派生一個新的類,無需對Client類做任何改動。

Shape應用程序

應用程序中有Circle、Square列表,需求是:繪制他們
從OCP原則考慮,設計方案如下,

class Shape{
draw();
}

class Circle extends Shape{
    draw(){
    
    }
}

class Square extends Shape{
    draw(){

    }
}

Class DrawAllShape{
    void drawAllShapes(List<Shape> lists){
        for(Shape shape :lists){
            shape.draw();
        }
    }
}

根據此設計,如果新增一個Triangle類,只需新增代碼即可,無需改動上述代碼,達到了開閉原則。真的嗎???

並非100%封閉

如果需求要求所有圓必須在正方形之前繪制,那么DrawAllShape無法對這種變化做到封閉。要實現這個需求,我們需要修改DrawAllShape,使它首先掃描列表中的圓,然后在掃描所有的正方形。

預測變化和貼切的結構

一般來說,無論模塊是多么封閉,都會存在一些無法對之封閉的變化,沒有對於所有的情況都貼切的模型。
既然不能完全封閉,就要有策略的對待這個問題,設計人員必須對於他設計的模塊應該對哪種變化封閉作出選擇,他必須先猜測出最有可能發生的變化種類,然后構造抽象來隔離那些變化。這需要設計人員具備一些從經驗中獲得的預測能力。
遵循OCP的代價是昂貴的,創建正確的抽象是要花費開發時間和精力的,同時,那些抽象也增加了軟件設計的復雜性,開發人員有能力處理的抽象的數量也是有限的,顯然,我們希望把OCP的應用限定在可能會發生的變化上。
  • 只受一次愚弄
    最初編寫代碼的時候,假設變化不會發生,當變化發生了,我們就創建抽象來隔離以后發生的同類變化。
  • 刺激變化
    盡早查明可能發生的變化,盡早接受變化帶來的改變。

Shape改造

class Shape{
    draw();
    //precedes();
    precedes(OrderRule order){
    }
}
Class DrawAllShape{
    sort(list);
    void drawAllShapes(List<Shape> lists){
        for(Shape shape :lists){
            shape.draw();
        }
    }
}

precedes()考慮到枚舉排序的話違背了OCP,可以將規則定義起來,改造成precedes(OrderRule order),排序規則從OrderRule中讀取,此時對與Shape繪制順序的變化不封閉的唯一部分就是OrderRule。

結論

在許多方面,OCP都是面向對象設計的核心所在。遵循這個原則可以的帶來面向對象技術所聲稱的巨大好處(靈活性,可重用性,可維護性)。對於應用程序中的每個部分都肆意的進行抽象同樣不是一個好主意。正確的做法是,開發人員應該僅僅對程序中呈現出頻繁變化的那些部分做出抽象。拒絕不成熟的抽象和抽象本身一樣重要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM