面向對象設計的六大原則(SOLID原則)-——開閉原則

来源:https://www.cnblogs.com/forges/p/18067528
-Advertisement-
Play Games

開閉原則(Open-Closed Principle, OCP)是面向對象設計的五大SOLID原則之一。這個原則主張“軟體實體(類、模塊、函數等)應該對擴展開放,對修改關閉”。也就是說,軟體的設計應該允許在不修改原有代碼的情況下增加新的功能。這樣的設計有助於降低代碼的複雜性和維護成本,同時提高系統的 ...


開閉原則(Open-Closed Principle, OCP)是面向對象設計的五大SOLID原則之一。這個原則主張“軟體實體(類、模塊、函數等)應該對擴展開放,對修改關閉”。也就是說,軟體的設計應該允許在不修改原有代碼的情況下增加新的功能。這樣的設計有助於降低代碼的複雜性和維護成本,同時提高系統的可復用性和可維護性。

詳細解釋

開閉原則強調兩點:

  1. 對擴展開放:當需要增加新功能時,應該通過添加新的代碼來實現,而不是修改已有的代碼。這可以通過使用抽象、介面、繼承和多態等面向對象的技術來實現。

  2. 對修改關閉:已有的代碼,特別是那些已經經過測試和驗證的代碼,應該儘量避免修改。這樣可以減少引入新bug的風險,同時保持系統的穩定性。

遵循開閉原則可以帶來以下好處:

  • 提高可維護性:由於系統對修改關閉,因此可以減少因修改已有代碼而引入的錯誤。
  • 提高可擴展性:系統對擴展開放,使得添加新功能變得更加容易。
  • 降低代碼的耦合度:通過抽象和介面來定義系統的行為,可以減少類與類之間的直接依賴,從而降低代碼的耦合度。

應用場景及代碼示例(C#)

場景1:插件系統

假設我們有一個圖像處理系統,我們希望通過插件的方式來添加新的圖像處理功能。

代碼示例

public interface IImageFilter  
{  
    void ApplyFilter(Image image);  
}  
  
public class BrightnessFilter : IImageFilter  
{  
    public void ApplyFilter(Image image)  
    {  
        // 增加亮度的邏輯  
    }  
}  
  
public class ContrastFilter : IImageFilter  
{  
    public void ApplyFilter(Image image)  
    {  
        // 調整對比度的邏輯  
    }  
}  
  
public class ImageProcessor  
{  
    private List<IImageFilter> filters = new List<IImageFilter>();  
  
    public void AddFilter(IImageFilter filter)  
    {  
        filters.Add(filter);  
    }  
  
    public void ProcessImage(Image image)  
    {  
        foreach (var filter in filters)  
        {  
            filter.ApplyFilter(image);  
        }  
    }  
}  
  
// 使用示例  
var processor = new ImageProcessor();  
processor.AddFilter(new BrightnessFilter());  
processor.AddFilter(new ContrastFilter());  
var image = new Image(); // 假設有一個Image類  
processor.ProcessImage(image);

在這個例子中,ImageProcessor 類對擴展開放,因為我們可以很容易地添加新的濾鏡(通過實現 IImageFilter 介面)。同時,它對修改關閉,因為我們不需要修改 ImageProcessor 類來支持新的濾鏡。

場景2:策略模式

策略模式是一種常見的設計模式,用於根據不同的情況選擇不同的演算法或策略。這也符合開閉原則。

代碼示例

public interface ISortingStrategy  
{  
    void Sort(List<int> list);  
}  
  
public class BubbleSortStrategy : ISortingStrategy  
{  
    public void Sort(List<int> list)  
    {  
        // 冒泡排序的邏輯  
    }  
}  
  
public class QuickSortStrategy : ISortingStrategy  
{  
    public void Sort(List<int> list)  
    {  
        // 快速排序的邏輯  
    }  
}  
  
public class SortedList  
{  
    private ISortingStrategy sortingStrategy;  
  
    public SortedList(ISortingStrategy sortingStrategy)  
    {  
        this.sortingStrategy = sortingStrategy;  
    }  
  
    public void SetSortingStrategy(ISortingStrategy sortingStrategy)  
    {  
        this.sortingStrategy = sortingStrategy;  
    }  
  
    public void Sort(List<int> list)  
    {  
        sortingStrategy.Sort(list);  
    }  
}  
  
// 使用示例  
var sortedList = new SortedList(new BubbleSortStrategy());  
var numbers = new List<int> { 3, 1, 4, 1, 5, 9 };  
sortedList.Sort(numbers);  
  
// 更換排序策略  
sortedList.SetSortingStrategy(new QuickSortStrategy());  
sortedList.Sort(numbers);
 

在這個例子中,SortedList 類對排序策略的擴展開放,因為我們可以通過實現 ISortingStrategy 介面來添加新的排序演算法。同時,它對修改關閉,因為更換排序策略時不需要修改 SortedList 類的內部代碼。

當然,開閉原則可以應用於許多不同的場景。以下是一些額外的應用場景示例,以及相應的C#代碼:

場景3:日誌記錄系統

在一個大型系統中,日誌記錄是非常重要的。你可能想要根據不同的需求添加不同的日誌記錄器,比如文件日誌記錄器、控制台日誌記錄器或資料庫日誌記錄器。通過使用開閉原則,你可以輕鬆地添加新的日誌記錄器,而不需要修改現有的日誌記錄系統。

public interface ILogger  
{  
    void Log(string message);  
}  
  
public class FileLogger : ILogger  
{  
    public void Log(string message)  
    {  
        // 將日誌寫入文件的邏輯  
    }  
}  
  
public class ConsoleLogger : ILogger  
{  
    public void Log(string message)  
    {  
        Console.WriteLine(message);  
    }  
}  
  
public class LoggingSystem  
{  
    private readonly List<ILogger> loggers = new List<ILogger>();  
  
    public void RegisterLogger(ILogger logger)  
    {  
        loggers.Add(logger);  
    }  
  
    public void Log(string message)  
    {  
        foreach (var logger in loggers)  
        {  
            logger.Log(message);  
        }  
    }  
}  
  
// 使用示例  
var loggingSystem = new LoggingSystem();  
loggingSystem.RegisterLogger(new FileLogger());  
loggingSystem.RegisterLogger(new ConsoleLogger());  
loggingSystem.Log("This is a log message.");

在這個例子中,LoggingSystem 類對日誌記錄器的擴展開放,因為我們可以實現 ILogger 介面來創建新的日誌記錄器,並將其註冊到系統中。同時,它對修改關閉,因為添加新的日誌記錄器不需要修改 LoggingSystem 類的代碼。

場景4:資料庫訪問層

在構建應用程式時,你可能需要訪問不同的資料庫,比如SQL Server、MySQL或Oracle。通過使用開閉原則,你可以設計一個資料庫訪問層,該層對不同類型的資料庫擴展開放,而對現有代碼的修改關閉。

代碼示例

public interface IDatabase  
{  
    void Connect();  
    void ExecuteQuery(string query);  
    void Close();  
}  
  
public class SqlServerDatabase : IDatabase  
{  
    public void Connect()  
    {  
        // 連接到SQL Server的邏輯  
    }  
  
    public void ExecuteQuery(string query)  
    {  
        // 在SQL Server上執行查詢的邏輯  
    }  
  
    public void Close()  
    {  
        // 關閉SQL Server連接的邏輯  
    }  
}  
  
public class MySqlDatabase : IDatabase  
{  
    public void Connect()  
    {  
        // 連接到MySQL的邏輯  
    }  
  
    public void ExecuteQuery(string query)  
    {  
        // 在MySQL上執行查詢的邏輯  
    }  
  
    public void Close()  
    {  
        // 關閉MySQL連接的邏輯  
    }  
}  
  
public class DatabaseManager  
{  
    private IDatabase database;  
  
    public DatabaseManager(IDatabase database)  
    {  
        this.database = database;  
    }  
  
    public void PerformQuery(string query)  
    {  
        database.Connect();  
        database.ExecuteQuery(query);  
        database.Close();  
    }  
}  
  
// 使用示例  
var sqlServerDb = new SqlServerDatabase();  
var databaseManager = new DatabaseManager(sqlServerDb);  
databaseManager.PerformQuery("SELECT * FROM Users");  
  
// 切換到MySQL資料庫  
var mySqlDb = new MySqlDatabase();  
databaseManager = new DatabaseManager(mySqlDb);  
databaseManager.PerformQuery("SELECT * FROM Users");

在這個例子中,DatabaseManager 類對不同類型的資料庫擴展開放,因為我們可以通過實現 IDatabase 介面來創建新的資料庫訪問類。同時,它對修改關閉,因為切換資料庫類型不需要修改 DatabaseManager 類的代碼。實際上,在實際應用中,你可能會使用依賴註入框架來動態地註入不同的資料庫實現,而不是像示例中那樣手動創建和切換它們。

public interface ISortingStrategy { void Sort(List<int> list); } public class BubbleSortStrategy : ISortingStrategy { public void Sort(List<int> list) { // 冒泡排序的邏輯 } } public class QuickSortStrategy : ISortingStrategy { public void Sort(List<int> list) { // 快速排序的邏輯 } } public class SortedList { private ISortingStrategy sortingStrategy; public SortedList(ISortingStrategy sortingStrategy) { this.sortingStrategy = sortingStrategy; } public void SetSortingStrategy(ISortingStrategy sortingStrategy) { this.sortingStrategy = sortingStrategy; } public void Sort(List<int> list) { sortingStrategy.Sort(list); } } // 使用示例 var sortedList = new SortedList(new BubbleSortStrategy()); var numbers = new List<int> { 3, 1, 4, 1, 5, 9 }; sortedList.Sort(numbers); // 更換排序策略 sortedList.SetSortingStrategy(new QuickSortStrategy()); sortedList.Sort(numbers);


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 關於動態代理的一些知識,以及cglib與jdk動態代理的區別,在這一篇已經介紹過,不熟悉的可以先看下。 本篇我們來學習一下cglib的FastClass機制,這是cglib與jdk動態代理的一個主要區別,也是一個面試考點。 我們知道jdk動態代理是使用InvocationHandler介面,在 ...
  • 本文主要介紹了設計模式中的狀態模式,然後在這個基礎上介紹了Spring狀態機相關的概念,並根據常見的訂單流轉場景,介紹了Spring狀態機的使用方式。 ...
  • F-String(格式化字元串字面值)是在Python 3.6中引入的,它是一種非常強大且靈活的字元串格式化方法。 它允許你在字元串中嵌入表達式,這些表達式在運行時會被求值並轉換為字元串,這種特性使得F-String在編寫Python代碼時能夠更簡潔、更直觀地處理字元串。 本文總結了5個實用的F-S ...
  • 概述:在WPF中,通過使用不同的元素如Ellipse、Line、Rectangle等,可以輕鬆繪製各種圖形,包括圓、線條、橢圓、矩形、多邊形等。同時,通過TextBlock展示文字,Image展示圖片,以及Path創建路徑和曲線,使得圖形的繪製變得靈活多樣。通過簡單的XAML代碼,開發者可以快速構建 ...
  • 程式能運行,就是告訴你RZ10012,然後各種提示沒有了。 清理解決方案、電腦重啟了都沒有用,後來搜索到github,解決了,記一下: 關閉vs 刪除文件夾 .vs,bin,object 打開vs,重新生成解決方案 也是醉了。 文字少的博文不允許投稿到該網站分類? 知道什麼叫短小精悍嗎?知道什麼叫短 ...
  • 11.1.0-beta1 Avalonia 是 dotnet 的跨平臺 UI 框架,提供靈活的樣式系統,支持 Windows、macOS、Linux、iOS、Android 和 WebAssembly 等多種平臺。 Avalonia 已經成熟並已做好生產準備,已被 Schneider Electri ...
  • System.Diagnostics.DiagnosticSource 可以豐富地記錄程式中地日誌,包括不可序列化的類型(例如 HttpResponseMessage 或 HttpContext)。 System.Diagnostics.DiagnosticSource 通過訂閱發佈模式運行,我們可 ...
  • 開源項目地址:https://gitee.com/lowcodexaf/rules-engine-editor 前言 本項目是基於XAFBlazor的規則引擎編輯器,規則引擎採用的是微軟開源的RulesEngine RulesEngine項目地址:https://github.com/microso ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...