面向?qū)ο笤O(shè)計五大原則(2)—— 開閉原則

開閉原則的定義

開閉原則定義如下:

軟件中的對象(類,模塊,函數(shù)等等)應(yīng)該對于擴展是開放的,但是對于修改是封閉的

如何理解開閉原則

這個定義不能分開來理解,“對擴展開放,對修改封閉”,表達的是同一個含義,即“可以方便的通過添加類/模塊/函數(shù)就能夠擴展現(xiàn)有類/模塊/函數(shù)的功能,而不需要修改現(xiàn)有的代碼”

這個的含義十分抽象,它并沒有直接給開閉原則下定義,而是表述了一個符合開閉原則的設(shè)計應(yīng)該具備的特性。首先讓我們通過一個例子來看看怎樣的實現(xiàn)才是遵循開閉原則的。

考慮我們需要實現(xiàn)一個負責(zé)打印log的類,它支持多種不同風(fēng)格的log樣式,第一種實現(xiàn)如下:

public class Logger {
    
    private int mFormat;

    public void setFormat(int format) {
        this.mFormat = format;
    }
    
    public void print(String log) {
        System.out.println(format(log));
    }
    
    private String format(String log) {
        switch (mFormat) {
            case SHORT:
                return formatShort(log);
            case NORMAL:
                return formatNormal(log);
            case BEAUTY:
            default:
                return formatBeauty(log);
        }
    }
    ...
}

顯然,這個類是不符合開閉原則的,假設(shè)現(xiàn)在我們需要給Logger添加一種可以打印帶日期的log的能力,那么除了修改Loger.format函數(shù)之外,就沒有其他更好的方法了。
下面是第二種實現(xiàn)

public class Logger {

    public interface Formatter {
        String format(String log);
    }
    
    private Formatter mFormatter;

    public void setFormat(Formatter formatter) {
        this.mFormatter = formatter;
    }

    public void print(String log) {
        System.out.println(mFormatter.format(log));
    }
    ...
}

我們將Logger類中的format功能從直接實現(xiàn)改為委托給Formatter接口來實現(xiàn),這樣如果我們需要添加一種新的格式只需要創(chuàng)建一個實現(xiàn)了Formatter接口的類來提供這個功能,然后將其傳給Logger類即可,在這個過程中,完全不需要對類進行修改,這正與開閉原則的要求相吻合。

下面我們來比較一下兩種實現(xiàn),顯然,第二種實現(xiàn)是一種更優(yōu)的實現(xiàn)方式。原因如下:

  1. Logger類更加符合單一職責(zé)原則。format功能被從其中分離出去了,Logger類只負責(zé)打印。
  2. Logger類與外界耦合更少。在第一種實現(xiàn)中,調(diào)用者需要關(guān)心Logger是如何對代碼進行格式化的,如果要添加一種格式化策略,對調(diào)用者而言非常麻煩,而第二種實現(xiàn)中,調(diào)用者完全不用考慮這個問題,因為格式化的策略就是調(diào)用者提供的。

第二種實現(xiàn)具有這些優(yōu)點并不偶然,一個類/模塊想要達到開閉原則的要求,必須具備下面兩個特點

  1. 功能清晰、明確。這樣才能避免在擴展的時候?qū)ζ溥M行修改
  2. 更外界的接口簡單,清楚。這樣在才能夠方便的添加類來對其進行擴展。

這兩點實際上就是面向?qū)ο蟮脑O(shè)計最核心的要求 —— 高內(nèi)聚,低耦合,因此開閉原則是面向?qū)ο笤O(shè)計五大原則中的核心原則,其它原則實際上都是圍繞它展開的。

遵循開閉原則的優(yōu)點

遵循開閉原則的設(shè)計一般都具有以下的優(yōu)點

  1. 易擴展。開閉原則的定義就要求對擴展開放。
  2. 易維護。軟件開發(fā)中,對現(xiàn)有代碼的修改是一件很有風(fēng)險的事情,符合開閉原則的設(shè)計在擴展時無需修改現(xiàn)有代碼,規(guī)避了這個風(fēng)險,大大提交了可維護性。

如何遵循開閉原則

目前并沒有一個通用的方法來設(shè)計出一個遵循開閉原則的軟件,下面是我自己對這個問題的思考。

開閉原則重點強調(diào)的是類/模塊的擴展能力,所謂擴展,一定是由變化引起的,因此,在軟件設(shè)計的時候,我們要不斷的識別那些可能存在的易變的點,思索它們未來可能的變化,并針對這些變化做出有彈性的包裝,這樣一旦變化來臨時,才能達到開閉原則所要求的效果。

同時也要小心,一個軟件一般只有少數(shù)一部分是易變的,大部分都是穩(wěn)定不變的,我們在識別易變點時一定要仔細甄別,如果將很多不變的地方也進行包裝就會陷入過度設(shè)計的誤區(qū)。一個軟件不可能處處都符合開閉原則,我們只需要做到在易變的地方符合開閉原則即可。


PS: 面向?qū)ο笤O(shè)計五大原則的其它文章
面向?qū)ο笤O(shè)計五大原則(1)—— 單一職責(zé)原則

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容