C# 实例解释面向对象编程中的开闭原则
在面向对象编程中,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();
}
修改后的 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 类也要对应做一些修改:
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# 代码示例简明地诠释了它的含意和实现,希望对您有所帮助。
作者 : 技术译民
出品 : 技术译站
参考文档:
- https://en.wikipedia.org/wiki/SOLID
- https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design
C# 实例解释面向对象编程中的开闭原则的更多相关文章
- C# 实例解释面向对象编程中的单一功能原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- C# 实例解释面向对象编程中的里氏替换原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- C# 实例解释面向对象编程中的接口隔离原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- C# 实例解释面向对象编程中的依赖反转原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- 聊一聊开闭原则(OCP).
目录 简述 最早提出(梅耶开闭原则) 重新定义(多态开闭原则) 深入探讨 OCP的两个特点 对外扩展开放(Open for extension) 对内修改关闭 抽象 关闭修改.对外扩展? 简述 在面向 ...
- C#中面向对象编程中的函数式编程详解
介绍 使用函数式编程来丰富面向对象编程的想法是陈旧的.将函数编程功能添加到面向对象的语言中会带来面向对象编程设计的好处. 一些旧的和不太老的语言,具有函数式编程和面向对象的编程: 例如,Smallta ...
- Dart编程实例 - Dart 面向对象编程
Dart编程实例 - Dart 面向对象编程 class TestClass { void disp() { print("Hello World"); } } void main ...
- Java的开发—面向对象的7大原则之开闭原则(一)
开闭原则(Open Close Principle) 一.定义: 软件中的(类.模块.函数等等)应该对于扩展是开放的,对于修改时关闭的.意味着一个实体允许在不改变它的源代码的前提变更它的行为 这里的软 ...
- 【面向对象设计原则】之开闭原则(OCP)
开闭原则是面向对象设计的一个重要原则,其定义如下: 开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭.即软件实体应尽量在不修改原有代码的情况下进 ...
随机推荐
- sqlplus -S参数表示什么意思?
sqlplus -S , -S选项是静默模式,是Silent的缩写.在这种模式下将会以最精简的形式完成SQL*Plus的交互过程. -S模式多用于脚本模式.在命令行sqlplus -S还有可能出现卡住 ...
- Cannot uninstall 'pyparsing'. It is a distutils installed project
我的环境: [root@ansible ~]# python -V Python 2.7.5 [root@ansible ~]# cat /etc/redhat-release CentOS Linu ...
- Windows系统上搭建Clickhouse开发环境
Windows系统上搭建Clickhouse开发环境 总体思路 微软的开发IDE是很棒的,有两种:Visual Studio 和 VS Code,一个重量级,一个轻量级.近年来VS Code越来越受欢 ...
- nuxt 相关
https://github.com/xuqiang521/nuxt-ssr-demo https://www.cnblogs.com/laozhang-is-phi/p/10249248.html ...
- HDUA/B
同样求逆元的题目,费马的条件,首先要保证p为质数,然后保证a与p互素. 数据范围问题,要保证在数据范围内,所以要b先模上mod #include<bits/stdc++.h> using ...
- .Net 线程安全集合
.Net 提供了基于生产-消费模式的集合类,这些集合对多线程访问安全,定义在System.Collections.Concurrent名称空间中.这个名称空间中包括基础接口IProduceConsum ...
- go面试题-基础类
go基础类 1. go优势 * 天生支持并发,性能高 * 单一的标准代码格式,比其它语言更具可读性 * 自动垃圾收集比java和python更有效,因为它与程序同时执行 go数据类型 int stri ...
- Tomcat-如何在IDEA启动部署web模板
IDEA部署工程到Tomcat上运行 1,建议修改web工程对应的Tomcat运行实例名称 2,将需要部署的web工程添加到Tomcat运行实例中,添加或删除 Application context: ...
- java抽象类案例
1 package face_09; 2 /* 3 * 雇员示例: 4 * 需求:公司中程序员有姓名,工号,薪水,工作内容. 5 * 项目经理除了有姓名,工号,薪水,还有奖金,工作内容. 6 * 对给 ...
- 基于Redis&MySQL接口幂等性设计
基于Redis&MySQL接口幂等性设计 欲把相思说似谁,浅情人不知. 1.幂等 幂等性即多次调用接口或方法不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致. 2.幂等使用场景 前 ...