網站首頁 編程語言 正文
在面向對象編程領域中,單一功能原則(Single responsibility principle)規定每個類都應該有且僅有一個單一的功能,并且該功能應該由這個類完全封裝起來。
在面向對象編程中,SOLID 是五個設計原則的首字母縮寫,旨在使軟件設計更易于理解、靈活和可維護。這些原則是由美國軟件工程師和講師羅伯特·C·馬丁(Robert Cecil Martin)提出的許多原則的子集,在他2000年的論文《設計原則與設計模式》中首次提出。
SOLID 原則包含:
- S:單一功能原則(single-responsibility principle)
- O:開閉原則(open-closed principle)
- L:里氏替換原則(Liskov substitution principle)
- I:接口隔離原則(Interface segregation principle)
- D:依賴反轉原則(Dependency inversion principle)
本文我們來介紹單一功能原則。
單一功能原則
在面向對象編程領域中,單一功能原則(Single responsibility principle)規定每個類都應該有且僅有一個單一的功能,并且該功能應該由這個類完全封裝起來。所有它的(這個類的)服務都應該嚴密的和該功能平行(功能平行,意味著沒有依賴)。
這個術語由羅伯特·C·馬丁(Robert Cecil Martin)在他的《敏捷軟件開發,原則,模式和實踐》一書中的一篇名為『面向對象設計原則』的文章中提出。馬丁表述該原則是基于《結構化分析和系統規格》一書中的內聚原則(Cohesion)之上的。
馬丁把功能(職責)定義為:“改變的原因”,并總結出一個類或者模塊應該有且只有一個改變的原因。一個具體的例子就是,想象有一個用于編輯和打印報表的模塊。這樣的一個模塊存在兩個改變的原因。第一,報表的內容可以改變(編輯)。第二,報表的格式可以改變(打印)。這兩方面的改變會因為完全不同的起因而發生:一個是本質的修改,一個是表面的修改。單一功能原則認為這兩方面的問題事實上是兩個分離的功能,因此他們應該分離在不同的類或者模塊里。把具有不同的改變原因的事物耦合在一起的設計是糟糕的。
保持一個類專注于單一功能點的一個重要的原因是,它可以使類更加的健壯。回顧上面的例子,如果有一個對于報表“編輯”流程的修改,那么將存在極大的危險性,因為假設這兩個功能存在于同一個類中,修改報表的“編輯”流程會導致公共狀態或者依賴關系的改變,從而可能使“打印”功能的代碼無法正常運行。
C# 示例
例如,考慮這樣一個應用程序,它接受一組形狀(圓形和正方形),并計算該列表中所有形狀的面積之和。
首先,創建形狀類,并通過構造函數設置所需的參數。
對于正方形,需要知道它的邊長:
/// <summary> /// 正方形 /// </summary> class Square { public Square(double length) { SideLength = length; } public double SideLength { get; init; } }
對于圓形,需要它的半徑:
/// <summary> /// 圓形 /// </summary> class Circle { public Circle(double radius) { Radius = radius; } public double Radius { get; init; } }
接下來,創建 AreaCalculator 類,然后編寫邏輯以計算所有提供的形狀的面積。正方形的面積是用邊長的平方計算的,圓的面積由 π
乘以半徑的平方來計算的。
糟糕的示范
class AreaCalculator { private List<object> _shapes; public AreaCalculator(List<object> shapes) { _shapes = shapes; } /// <summary> /// 計算所有形狀的面積總和 /// </summary> /// <returns></returns> public double Sum() List<double> areas = new List<double>(); foreach (var item in _shapes) { if (item is Square s) { areas.Add(Math.Pow(s.SideLength, 2)); } else if (item is Circle c) areas.Add(Math.PI * Math.Pow(c.Radius, 2)); } return areas.Sum(); public string Output() return $"Sum of the areas of provided shapes: {Sum()}"; }
要使用 AreaCalculator 類,您需要實例化這個類,并傳入一個形狀列表,并顯示其輸出。
在此,我們傳入一個三個形狀的列表:一個半徑為 2 的圓,一個邊長為 5 的正方形,一個邊長為 6 的正方形。
static void Main(string[] args) { var shapes = new List<object> { new Circle(2), new Square(5), new Square(6) }; var areas = new AreaCalculator(shapes); Console.WriteLine(areas.Output()); }
運行程序,您會看到如下的輸出:
Sum of the areas of provided shapes: 73.56637061435917
輸出正常,但這并不符合單一功能原則。因為 AreaCalculator 類既計算了所有形狀的面積之和,又處理了輸出數據的格式。
考慮這樣一個場景,假如想要輸出轉換為另一種格式呢,如 JSON。我們就需要去修改 AreaCalculator 類,這樣本來是為了修改輸出數據的格式,卻可能會影響到計算的邏輯,這明顯違反了單一功能原則。
正確的示范
AreaCalculator 類應該只關心計算提供的形狀的面積之和,不應該關心輸出什么格式。
下面我們來做一些修改,刪除 AreaCalculator 類中的 Output
方法:
class AreaCalculator { private List<object> _shapes; public AreaCalculator(List<object> shapes) { _shapes = shapes; } /// <summary> /// 計算所有形狀的面積總和 /// </summary> /// <returns></returns> public double Sum() List<double> areas = new List<double>(); foreach (var item in _shapes) { if (item is Square s) { areas.Add(Math.Pow(s.SideLength, 2)); } else if (item is Circle c) areas.Add(Math.PI * Math.Pow(c.Radius, 2)); } return areas.Sum(); }
并新增一個 SumCalculatorOutputter 類來專門處理輸出格式的邏輯:
class SumCalculatorOutputter { protected AreaCalculator _calculator; public SumCalculatorOutputter(AreaCalculator calculator) { _calculator = calculator; } public string String() return $"Sum of the areas of provided shapes: {_calculator.Sum()}"; public string JSON() var data = new { Sum = _calculator.Sum() }; return System.Text.Json.JsonSerializer.Serialize(data); }
此時我們再來修改一下 Main
中的調用:
static void Main(string[] args) { var shapes = new List<object> { new Circle(2), new Square(5), new Square(6) }; var areaCalculator = new AreaCalculator(shapes); var outputer = new SumCalculatorOutputter(areaCalculator); Console.WriteLine(outputer.JSON()); Console.WriteLine(outputer.String()); }
運行程序,輸出結果如下:
{"Sum":73.56637061435917}
Sum of the areas of provided shapes: 73.56637061435917
現在,AreaCalculator 類處理計算邏輯,SumCalculatorOutputter 類處理輸出格式,它們各司其職,遵循了單一功能原則。
總結
本文我介紹了 SOLID 原則中的單一功能原則(single-responsibility principle),并通過 C# 代碼示例簡明地詮釋了它的含意和實現,希望對您有所幫助。
參考文檔:
原文鏈接:https://www.cnblogs.com/ittranslator
相關推薦
- 2023-01-23 Electron打包React生成桌面應用方法詳解_React
- 2022-01-18 ES6新語法(解構賦值、模板字符串)
- 2022-04-05 svn使用命令忽略指定目錄 svn propset svn:ignore “要忽略的目錄“ .
- 2022-07-20 Python實現向PPT中插入表格與圖片的方法詳解_python
- 2022-06-14 .NET?Core(.NET6)中gRPC使用實踐_實用技巧
- 2022-10-19 Pandas如何將表格的前幾行生成html實戰案例_python
- 2023-07-06 mac配置idea自帶的maven3環境變量
- 2022-09-03 Golang棧結構和后綴表達式實現計算器示例_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支