C#面向?qū)ο缶幊讨虚_閉原則的示例詳解
在面向?qū)ο缶幊讨校?strong>SOLID 是五個設(shè)計原則的首字母縮寫,旨在使軟件設(shè)計更易于理解、靈活和可維護(hù)。這些原則是由美國軟件工程師和講師羅伯特·C·馬丁(Robert Cecil Martin)提出的許多原則的子集,在他2000年的論文《設(shè)計原則與設(shè)計模式》中首次提出。
SOLID 原則包含:
- S:單一功能原則(single-responsibility principle)
- O:開閉原則(open-closed principle)
- L:里氏替換原則(Liskov substitution principle)
- I:接口隔離原則(Interface segregation principle)
- D:依賴反轉(zhuǎn)原則(Dependency inversion principle)
本文我們來介紹開閉原則。
開閉原則
在面向?qū)ο缶幊填I(lǐng)域中,開閉原則 (open-closed principle, OCP) 規(guī)定“軟件中的對象(類,模塊,函數(shù)等等)應(yīng)該對于擴(kuò)展是開放的,而對于修改是封閉的”,這意味著一個實體是允許在不改變它的源代碼的前提下變更它的行為。該特性在產(chǎn)品化的環(huán)境中是特別有價值的,在這種環(huán)境中,改變源代碼需要代碼審查,單元測試以及諸如此類的用以確保產(chǎn)品使用品質(zhì)的過程。遵循開閉原則的代碼在擴(kuò)展時并不發(fā)生改變,因此無需這些過程。
具體到類,也就是說,在不修改類本身代碼的情況下,應(yīng)該是可以擴(kuò)展它的行為的。
C# 示例
讓我們回顧一下上一篇文章單一功能原則中提到的 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();
}
}
對于上面的計算方法,考慮這樣一種場景,用戶想要計算一些其它形狀的面積總和,比如三角形、矩形、五邊形等等…… 您將不得不反復(fù)編輯此類以添加更多的 if/else 塊,這就違反了開閉原則。
改進(jìn)
一個更好的做法是,將計算每個形狀的面積的邏輯從 AreaCalculator 類中移除,并將其添加到對應(yīng)每個形狀的類中。我們可以定義一個帶有 CalcArea 方法的接口 IShape,然后讓每個形狀都實現(xiàn)這個接口。
接口 IShape:
interface IShape
{
/// <summary>
/// 計算面積
/// </summary>
/// <returns></returns>
double CalcArea();
}
修改后的 Square 和 Circle 類:
/// <summary>
/// 正方形
/// </summary>
class Square : IShape
{
public Square(double length)
{
SideLength = length;
}
public double SideLength { get; init; }
public double CalcArea()
{
return Math.Pow(SideLength, 2);
}
}
/// <summary>
/// 圓形
/// </summary>
class Circle : IShape
{
public Circle(double radius)
{
Radius = radius;
}
public double Radius { get; init; }
public double CalcArea()
{
return Math.PI * Math.Pow(Radius, 2);
}
}
AreaCalculator 類也要對應(yīng)做一些修改:
class AreaCalculator
{
private List<IShape> _shapes;
public AreaCalculator(List<IShape> shapes)
{
_shapes = shapes;
}
/// <summary>
/// 計算面積總和
/// </summary>
/// <returns></returns>
public double Sum()
{
List<double> areas = new List<double>();
foreach (var item in _shapes)
{
areas.Add(item.CalcArea());
}
return areas.Sum();
}
}
此時,如果我們有一個新的形狀需要進(jìn)行計算,我們可以直接添加一個實現(xiàn)了接口 IShape 的新類,而無需修改 AreaCalculator 類的代碼,比如添加一個長方形類:
/// <summary>
/// 長方形
/// </summary>
class Rectangle : IShape
{
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
public double Width { get; init; }
public double Height { get; init; }
public double CalcArea()
{
return Width * Height;
}
}
處理輸出格式的 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<IShape> {
new Circle(2),
new Square(5),
new Rectangle(2,3)
};
var areaCalculator = new AreaCalculator(shapes);
var outputer = new SumCalculatorOutputter(areaCalculator);
Console.WriteLine(outputer.JSON());
Console.WriteLine(outputer.String());
}
運行一下,輸出結(jié)果為:
{"Sum":43.56637061435917}
Sum of the areas of provided shapes: 43.56637061435917
現(xiàn)在,這些類的設(shè)計,既遵循了單一功能原則,又遵循了開閉原則。
總結(jié)
本文我介紹了 SOLID 原則中的開閉原則 (open-closed principle),并通過 C# 代碼示例簡明地詮釋了它的含意和實現(xiàn),希望對您有所幫助。
參考文檔:
到此這篇關(guān)于C#面向?qū)ο缶幊讨虚_閉原則的示例詳解的文章就介紹到這了,更多相關(guān)C#開閉原則內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#/VB.NET實現(xiàn)將XML轉(zhuǎn)為PDF
可擴(kuò)展標(biāo)記語言(XML)文件是一種標(biāo)準(zhǔn)的文本文件,它使用特定的標(biāo)記來描述文檔的結(jié)構(gòu)以及其他特性。本文將利用C#實現(xiàn)XML文件轉(zhuǎn)PDF?,需要的可以參考一下2022-03-03

