在面向对象编程中,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)

本文我们来介绍开闭原则

开闭原则

在面向对象编程领域中,开闭原则 (open-closed principle, OCP) 规定软件中的对象(类,模块,函数等等)应该对于扩展是开放的,而对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用品质的过程。遵循开闭原则的代码在扩展时并不发生改变,因此无需这些过程。

具体到类,也就是说,在不修改类本身代码的情况下,应该是可以扩展它的行为的。

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();
}
}

对于上面的计算方法,考虑这样一种场景,用户想要计算一些其它形状的面积总和,比如三角形、矩形、五边形等等…… 您将不得不反复编辑此类以添加更多的 if/else 块,这就违反了开闭原则

改进

一个更好的做法是,将计算每个形状的面积的逻辑从 AreaCalculator 类中移除,并将其添加到对应每个形状的类中。我们可以定义一个带有 CalcArea 方法的接口 IShape,然后让每个形状都实现这个接口。

接口 IShape

interface IShape
{
/// <summary>
/// 计算面积
/// </summary>
/// <returns></returns>
double CalcArea();
}

修改后的 SquareCircle 类:

/// <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 类也要对应做一些修改:

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();
}
}

此时,如果我们有一个新的形状需要进行计算,我们可以直接添加一个实现了接口 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());
}

运行一下,输出结果为:

{"Sum":43.56637061435917}
Sum of the areas of provided shapes: 43.56637061435917

现在,这些类的设计,既遵循了单一功能原则,又遵循了开闭原则

总结

本文我介绍了 SOLID 原则中的开闭原则 (open-closed principle),并通过 C# 代码示例简明地诠释了它的含意和实现,希望对您有所帮助。

作者 : 技术译民

出品 : 技术译站

参考文档:

C# 实例解释面向对象编程中的开闭原则的更多相关文章

  1. C# 实例解释面向对象编程中的单一功能原则

    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...

  2. C# 实例解释面向对象编程中的里氏替换原则

    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...

  3. C# 实例解释面向对象编程中的接口隔离原则

    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...

  4. C# 实例解释面向对象编程中的依赖反转原则

    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...

  5. 聊一聊开闭原则(OCP).

    目录 简述 最早提出(梅耶开闭原则) 重新定义(多态开闭原则) 深入探讨 OCP的两个特点 对外扩展开放(Open for extension) 对内修改关闭 抽象 关闭修改.对外扩展? 简述 在面向 ...

  6. C#中面向对象编程中的函数式编程详解

    介绍 使用函数式编程来丰富面向对象编程的想法是陈旧的.将函数编程功能添加到面向对象的语言中会带来面向对象编程设计的好处. 一些旧的和不太老的语言,具有函数式编程和面向对象的编程: 例如,Smallta ...

  7. Dart编程实例 - Dart 面向对象编程

    Dart编程实例 - Dart 面向对象编程 class TestClass { void disp() { print("Hello World"); } } void main ...

  8. Java的开发—面向对象的7大原则之开闭原则(一)

    开闭原则(Open Close Principle) 一.定义: 软件中的(类.模块.函数等等)应该对于扩展是开放的,对于修改时关闭的.意味着一个实体允许在不改变它的源代码的前提变更它的行为 这里的软 ...

  9. 【面向对象设计原则】之开闭原则(OCP)

    开闭原则是面向对象设计的一个重要原则,其定义如下: 开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭.即软件实体应尽量在不修改原有代码的情况下进 ...

随机推荐

  1. Java 递归 常见24道题目 总结

    1.N个台阶的走法递归[这里设为10个台阶] /** * N个台阶的走法递归 * <p> * 有个楼梯,台阶有10个,每次可以跳上1阶 或者 2阶 ,那么台阶的走法一共有多少种 */ @T ...

  2. linux光标命令快捷键(常用)

    Ctrl+a 移动到首行 Ctrl+e 移动到尾行 Ctrl+u 将当前光标后面的内容全部删除 (剪辑) ctrl+k 将当前光标前面的内容全部删除 (剪辑) Ctrl+→(左右同理) 移动到下个空格 ...

  3. Mysql设计遵循规则

    为什么要优化系统的吞吐量瓶颈往往出现在数据库的访问速度上随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢数据是存放在磁盘上的,读写速度无法和内存相比 如何优化设计数据库时:数据库表. ...

  4. 如何对K8s进行考核?Kuberhealthy来打个样!

    2019年11月,在圣地亚哥KubeCon,我们发布了kuberhealth 2.0.0--将kuberhealthy作为合成监测的Kubernetes operator.这个新功能为开发人员提供了创 ...

  5. 利用Spring AOP切面对用户访问进行监控

    开发系统时往往需要考虑记录用户访问系统查询了那些数据.进行了什么操作,尤其是访问重要的数据和执行重要的操作的时候将数记录下来尤显的有意义.有了这些用户行为数据,事后可以以用户为条件对用户在系统的访问和 ...

  6. CTF-sql-宽字节注入

    本文章主要涉及sql宽字节注入注入的原理讲解,如有错误,望指出.(附有目录,如需查看请点右下角) 一.首先介绍一下本篇文章所用到的知识点: 常用到的url编码: 空格:%20 单引号:%27 在sql ...

  7. 在pyqt5中展示pyecharts生成的图像

    技术背景 虽然现在很少有人用python去做一些图形化的界面,但是不得不说我们在日常大部分的软件使用中都还是有可视化与交互这样的需求的.因此pyqt5作为一个主流的python的GUI框架地位是非常重 ...

  8. 《剑指offer》面试题32 - III. 从上到下打印二叉树 III

    问题描述 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推. 例如: 给定二叉树: [3,9,20, ...

  9. DEEP LEARNING WITH PYTORCH: A 60 MINUTE BLITZ | TORCH.AUTOGRAD

    torch.autograd 是PyTorch的自动微分引擎,用以推动神经网络训练.在本节,你将会对autograd如何帮助神经网络训练的概念有所理解. 背景 神经网络(NNs)是在输入数据上执行的嵌 ...

  10. cp 不提示按y

    yes|cp index.html.j2   yml -rf \cp index.html.j2   yml/ 两个效果是一样的