iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Software Development

輕鬆學習設計模式Design Pattern系列 第 27

Day 27 開放封閉原則 Open-Closed Principle

  • 分享至 

  • xImage
  •  

在軟體設計中,我們經常面對需求變更的挑戰。想像一下,當客戶突然提出新需求時,你的系統卻因為架構過於死板,導致每次要修改功能都得重新調整大量程式碼。這不僅會耗費時間,還會增加出錯的機會。這時候「開放封閉原則 (Open-Closed Principle, OCP)」就能派上用場,幫助我們的程式保持靈活性,同時又能控制變更帶來的風險。

什麼是開放封閉原則?

開放封閉原則,簡單來說就是軟體應該對擴展開放,對修改封閉。也就是說我們應該設計程式,使其能夠在不修改既有程式碼的情況下,透過擴展來新增功能。

換句話說,當我們的需求改變時,應該可以透過增加新類別或新功能來解決,而不是去修改現有的邏輯。這樣的好處是,既能保護原有系統的穩定性,又能快速適應變化。

開放封閉原則的例子

讓我們來看一個不符合開放封閉原則的例子,來感受這個原則的意義。

錯誤的設計,違反開放封閉原則

假設我們在設計一個圖形繪製程式,原本只需要支援兩種圖形——圓形和方形,我們的程式可能會這樣寫:

enum ShapeType {
    Circle,
    Square
};

class ShapeDrawer {
public:
    void drawShape(ShapeType type) {
        if (type == Circle) {
            // 畫圓形的邏輯
        } else if (type == Square) {
            // 畫方形的邏輯
        }
    }
};

這段程式碼運作良好,但當需求改變,客戶希望支援更多的圖形類型時,我們就必須不斷修改 ShapeDrawer 類別,加入新的條件分支。如果圖形種類越來越多,例如三角形、橢圓與菱形等,這段程式碼會變得越來越臃腫且難以維護。

上述例子顯然違反了開放封閉原則。因為每當我們需要新增一種新圖形,都得進行程式碼修改,這不僅增加了錯誤的風險,也讓系統變得更加脆弱。理想的情況下,我們應該能在不改動既有程式碼的情況下,輕鬆地增加新圖形的繪製功能。

正確的設計,遵守開放封閉原則

為了符合開放封閉原則,我們可以運用抽象類別與多型的設計來解決這個問題:

class Shape {
public:
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    void draw() const override {
        // 畫圓形的邏輯
    }
};

class Square : public Shape {
public:
    void draw() const override {
        // 畫方形的邏輯
    }
};

class ShapeDrawer {
public:
    void drawShape(const Shape& shape) {
        shape.draw();
    }
};

在這個設計中,ShapeDrawer 不再依賴於具體的圖形類型,所有圖形的繪製邏輯都由各自的類別來負責。如果我們需要新增一種新圖形,例如三角形,我們只需新增一個 Triangle 類別,實作其 draw 方法,而不需要修改 ShapeDrawer 類別。這樣我們就可以輕鬆擴展功能,而不必改動既有的程式碼,符合了開放封閉原則。

為什麼這麼做?

開放封閉原則帶來的最大好處就是系統的穩定性與可擴展性。當我們能夠在不修改現有程式碼的情況下擴展功能時,就能減少意外錯誤的風險,也能保持系統的穩定性。這在大型專案或持續演進的系統中顯得重要。

同時,這樣的設計還讓我們的程式更加容易維護和理解。每個圖形的繪製邏輯都被封裝在各自的類別中,遵循單一職責原則 (Single Responsibility Principle),不會讓 ShapeDrawer 類別變得臃腫不堪。

當然,開放封閉原則也有其限制,特別是當我們過度抽象時,可能會使系統設計變得過於複雜。在小型專案中,這種設計的好處可能不那麼明顯,但隨著系統規模增大,這種方式的優勢會逐漸顯現。

實際應用

開放封閉原則廣泛應用於各種場景,尤其是在框架設計第三方擴展時非常實用。舉例來說,許多應用程式框架都提供了一系列的抽象介面,開發者可以在不修改框架核心程式碼的情況下,透過實作這些介面來擴展功能,這正是開放封閉原則的應用。

同樣地,在一些策略模式或工廠模式的應用中,我們也會看到開放封閉原則的影子。無論是新增業務邏輯、加入新的功能模組,還是替換現有功能,遵守這個原則都能讓我們的系統保持穩定且靈活。

更多C++語言相關的文章,歡迎追蹤我的部落格
https://shengyu7697.github.io/open-closed-principle/


上一篇
Day 26 單一職責原則 Single Responsibility Principle
下一篇
Day 28 里氏替換原則 Liskov Substitution Principle
系列文
輕鬆學習設計模式Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言