【设计模式笔记02】:面向对象设计原则-开闭原则
面向对象设计原则是编程时应遵循的准则,也是设计模式的基础,包括开闭原则、依赖倒置原则等七大原则。这些原则相互依赖,旨在提高软件的可复用性和可维护性。开闭原则是核心原则,要求系统对扩展开放、对修改关闭,可通过抽象层和实现层分离来实现。以CRM系统图表显示为例,通过引入抽象图表类,使系统在添加新图表时无需修改原有代码,体现了开闭原则及其他相关原则的应用。
·
文章目录
第二章:面向对象设计原则
一、 概述
1. 基本概念
- 设计原则是程序员在编程时应当遵守的准则,也是各种设计模式的基础(或者说是设计的依据)。
- 面向对象设计原则不是孤立存在的,它们相互依赖,相互补充。
2. 七大设计原则
| 设计原则名称 | 设计原则简介 | 重要性 |
|---|---|---|
| 1. 开闭原则 | 软件实体对扩展是开放的,但对修改是关闭的。 | ★★★★★ |
| 2. 依赖倒置原则 | 要针对于抽象层编程,高层不应依赖底层。 | ★★★★★ |
| 3. 里氏代换原则 | 所有引用基类的地方必须能透明地使用其子类对象。 | ★★★★☆ |
| 4. 合成-聚合复用原则 | 在系统中应尽量多使用组合和聚合关联关系,尽量少使用甚至不使用继承关系。 | ★★★★☆ |
| 5. 单一职责原则 | 类的职责要单一,不能将太多的职责放在一个类中。 | ★★★★☆ |
| 6. 迪米特法则 | 一个软件实体对其他实体的引用越少越好,两个类尽量通过第三者发生间接交互。(俗语:不要与陌生人说话)。 | ★★★☆☆ |
| 7. 接口隔离原则 | 使用多个专门的接口来取代一个统一的接口。 | ★★☆☆☆ |
3. 软件的可复用性和可维护性
- 软件的复用:拥有众多优点,如可以提高软件的开发效率、提高软件质量、节约开发成本等。恰当的复用还可以改善系统的可维护性。
- 面向对象设计的目标:在于实现支持可维护性的复用。
- 在面向对象的设计里,可维护性复用都是以面向对象设计原则为基础的。遵循这些原则可以有效地提高系统的复用性,同时提高系统的可维护性。
二、 开闭原则 (OCP)
1. 定义
- 一个软件实体应当对扩展开放,对修改关闭 (Open for extension, Closed for modification)。
- 核心思想:在设计一个模块的时候,应该使这个模块可以在不被修改的前提下被扩展。即在不修改源代码的情况下改变这个模块的行为。
- 该原则由 Bertrand Meyer 于1988年提出。
2. 分析
- 核心问题:任何软件都面临需求变更的问题。当软件系统需要面对新的需求时,我们应该尽量保证系统的设计框架是稳定的。
- 重要性:随着软件规模越来越大,软件寿命越来越长,软件维护成本也越来越高。设计满足开闭原则的软件系统也变得越来越重要。
- 优点:如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,且在扩展时无须修改现有代码,使得软件系统具备较好的稳定性和延续性。
3. 实现方法
- 在Java、C#等编程语言中,可以通过定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中来完成。
- 很多面向对象编程语言都提供了接口、抽象类等机制,这是实现开闭原则的基础。
- 当需要修改系统的行为时,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可。这实现了在不修改已有代码的基础上扩展系统功能的目标,达到了开闭原则的要求。
4. 核心地位
- 开闭原则是面向对象的可复用设计的基石(根本原则)。
- 其他设计原则(里氏代换原则、依赖倒置原则、合成/聚合复用原则、迪米特法则、接口隔离原则)都是实现开闭原则的手段和工具。
5. 示例:CRM系统图表显示
-
初始设计(问题)
- 一个客户关系管理(CRM)系统需要显示饼状图、柱状图等多种图表。
ChartDisplay类中有一个display(String type)方法,内部使用if-else if逻辑判断type字符串,然后new出具体的图表对象(如BarChart)并调用其display方法。
-
存在的问题
display()方法针对每一个图表类进行编程,这导致增加新的图表类就不得不修改源代码。- 例如,要增加一个新的
LineChart(折线图),就需要修改ChartDisplay类的display()方法,增加一个新的else if判断逻辑。 - 这明显违反了开闭原则。
-
重构方案
- 目标:达到在增加新的图表类时无须修改
ChartDisplay类的源代码。 - 引入抽象层:创建一个抽象图表类
AbstractChart,其中包含一个抽象的display()方法。 - 具体实现:让
PieChart、BarChart等具体的图表类继承自AbstractChart并实现各自的display()方法。 - 修改调用方:
ChartDisplay类不再依赖具体的图表类,而是依赖于AbstractChart抽象类。它持有一个AbstractChart的引用,其display()方法直接调用这个引用的display()方法即可。
- 目标:达到在增加新的图表类时无须修改

重构后的UML类图。
ChartDisplay类聚合了一个AbstractChart抽象类的对象。PieChart和BarChart类都继承自AbstractChart。ChartDisplay的display方法通过调用chart.display()来实现功能。
- 总结
- 通过引入抽象层,将系统的变化部分(各种具体的图表)封装起来,使得核心逻辑(
ChartDisplay)依赖于一个不变的抽象,从而实现了开闭原则。 - 这个重构过程也体现了依赖倒置原则(依赖于抽象而非具体)和里氏代换原则(任何
AbstractChart子类都可以被ChartDisplay使用)。
- 通过引入抽象层,将系统的变化部分(各种具体的图表)封装起来,使得核心逻辑(
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐

所有评论(0)