软件设计原则(五) 开闭原则
一、简介
概念:
软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的。
问题由来:
- 直接在原代码上修改会有风险,可能导致原先功能出现不可预知错误;
- 如果新需求更改频繁,对原先功能就修改越频繁;
- 随着功能的增多,模块的大小也越来越臃肿;
实现方式:
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。(用抽象构建框架,用实现扩展细节)。
二、示例
下面举例说明什么是开闭原则, 以计算不同图形的面积为例,代码如下:
public class OpenClosed {public static void main(String[] args) {draw(GraphicalEnum.CIRCLE);draw(GraphicalEnum.TRIANGLE);}public static void draw(GraphicalEnum graphicalEnum) {switch (graphicalEnum) {case TRIANGLE:Triangle triangle = new Triangle(2, 4);triangle.getArea();break;case CIRCLE:Circle circle = new Circle(2);circle.getArea();break;default:break;}}}enum GraphicalEnum {CIRCLE, TRIANGLE
}/*** 圆形*/
class Circle {int r;public Circle(int r) {super();this.r = r;}public double getArea() {double area = Math.PI * Math.pow(r, 2);System.out.println("计算圆形面积: " + area);return area;}}/*** 三角形*/
class Triangle {int width;int height;public Triangle(int width, int height) {super();this.width = width;this.height = height;}public double getArea() {double area = width * height / 2;System.out.println("计算三角形面积: " + area);return area;}}
运行结果:
通过上面的代码已经成功完成了计算圆形和三角形的面积,但是这样的设计是否合理?假如我需要增加计算长方形、正方形的面积,很显然需要修改上面的很多代码,修改量非常大,如下增加计算正方形面积:
public class OpenClosed {public static void main(String[] args) {draw(GraphicalEnum.CIRCLE);draw(GraphicalEnum.TRIANGLE);draw(GraphicalEnum.SQUARE);}public static void draw(GraphicalEnum graphicalEnum) {switch (graphicalEnum) {case TRIANGLE:Triangle triangle = new Triangle(2, 4);triangle.getArea();break;case CIRCLE:Circle circle = new Circle(2);circle.getArea();break;case SQUARE:Square square = new Square(4);square.getArea();break;default:break;}}}enum GraphicalEnum {CIRCLE, TRIANGLE, SQUARE
}/*** 圆形*/
class Circle {int r;public Circle(int r) {super();this.r = r;}public double getArea() {double area = Math.PI * Math.pow(r, 2);System.out.println("计算圆形面积: " + area);return area;}}/*** 三角形*/
class Triangle {int width;int height;public Triangle(int width, int height) {super();this.width = width;this.height = height;}public double getArea() {double area = width * height / 2;System.out.println("计算三角形面积: " + area);return area;}}/*** 正方形*/
class Square {int width;public Square(int width) {super();this.width = width;}public double getArea() {double area = Math.pow(width, 2);System.out.println("计算正方形面积: " + area);return area;}
}
可见,修改的地方包括提供者,也包括使用方,按照开闭原则:“对扩展开放,对修改关闭”,上面的代码明显违反了开闭原则,在扩展功能的同时需要修改原先运行正常的代码,如果扩展的功能越多,那么修改后导致的问题可能就会越多。试想一下,是否可以利用多态的思想实现如上的需求,并且扩展性是不是也变好了?答案是肯定的,下面我们将定义一个抽象类,然后各个子类去继承该抽象类,抽象类定义好了一些规则,子类只需要根据自身需要重写方法即可。
三、优化
优化后的类图大致如下:
public class OpenClosed {public static void main(String[] args) {Circle circle = new Circle(2);draw(circle);Triangle triangle = new Triangle(2, 4);triangle.getArea();Square square = new Square(4);square.getArea();}public static void draw(Graphical graphical) {graphical.getArea();}
}/*** 图形抽象类,方便后期扩展功能*/
abstract class Graphical {public abstract double getArea();
}/*** 圆形*/
class Circle extends Graphical {int r;public Circle(int r) {super();this.r = r;}@Overridepublic double getArea() {double area = Math.PI * Math.pow(r, 2);System.out.println("计算圆形面积: " + area);return area;}}/*** 三角形*/
class Triangle extends Graphical {int width;int height;public Triangle(int width, int height) {super();this.width = width;this.height = height;}@Overridepublic double getArea() {double area = width * height / 2;System.out.println("计算三角形面积: " + area);return area;}}/*** 正方形*/
class Square extends Graphical {int width;public Square(int width) {super();this.width = width;}@Overridepublic double getArea() {double area = Math.pow(width, 2);System.out.println("计算正方形面积: " + area);return area;}
}
运行结果:
以后如果想扩展更多的图形的话,只需要新增一个类继承抽象类即可,原先代码保持不变,这就是对扩展开放(针对提供者来说),对修改关闭(针对使用方来说)。
四、总结
开闭原则告诉我们,一个软件实体应该通过扩展来实现变化, 而不是通过修改已有的代码来实现变化。即:
- 用抽象构建框架,用实现扩展细节
优点:
- 可以提高代码的复用性;
- 增强可维护性和可扩展性;
- 通过扩展实现变化,保证对原先已有代码的影响降到最小;
- 遵守好了开闭原则,则能保证模块功能不会变得很臃肿;
开闭原则,不能说遵守不遵守,应该说遵守的或多或少,任何人都不一定对开闭原则做的很好,只能说尽量遵守得足够多,其实五项原则:单一职责、接口隔离、依赖倒置、里氏替换遵守的好的话,自然就遵守了开闭原则,这样的软件架构扩展性才会好一些。在实际工作中,或多或少接触过前人留下的代码需要维护,如果某一天新增需求了,如果作为维护人员,那么你想是通过扩展来实现新需求还是通过读懂前人代码然后进行修改来实现新需求,毋庸置疑,大家肯定都想直接新加一个方法就可以搞定新需求就好了,所以我们在工作中写代码的时候能尽量满足开闭原则,就一定要满足,提高代码可读和可维护性。
好了,以上只是笔者对开闭原则学习的一些总结,可能总结的还不够那么完善,欢迎大家一起补充,一起学习一起进步呀~~~
软件设计原则(五) 开闭原则相关推荐
- [设计原则] 六大设计原则之“开闭原则”
[设计原则] 六大设计原则之"开闭原则" 目录 [设计原则] 六大设计原则之"开闭原则" 什么是开闭原则 为什么使用开闭原则 如何使用开闭原则 注意事项 总结 ...
- Java设计原则之单一职责原则、开闭原则、里氏代换原则
文章目录 面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 面向对象设计原则概述 软件的可维护性(Maintainability)和可复用性(Reusability)是两个非常重要的用于衡量 ...
- 七大设计原则之开闭原则
一.开闭原则介绍 开闭原则(Open Closed Principle)是编程中最基础,也是最重要的设计原则.编程中遵循其他原则以及使用设计模式的目的就是遵循开闭原则. 一个软件实体如类,模块和函数应 ...
- 设计原则:开闭原则(OCP)
1.什么是开闭原则 开闭原则的英文是Open Closed Principle,缩写就是OCP.其定义如下: 软件实体(模块.类.方法等)应该"对扩展开放.对修改关闭". 从定义上 ...
- 设计模式-02.经典设计原则-第一节-单一职责原则,开闭原则,里式替换,接口隔离【万字长文系列】
文章目录 设计模式经典设计原则-第一节 单一职责原则(SRP) 如何理解单一职责原则? 如何判断类的职责是否足够单一? 类的职责是否设计得越单一越好? 开闭原则(OCP) 如何理解"对扩展开 ...
- Java面向对象设计原则1——开闭原则
在我们学习面向对象编程的时候,总会出现一些问题,好比以前刚刚写好的代码,上线测试可以.正常运行,突然有一天说要加一个功能,改完之后,发现以前正常运行的功能不能用了,类似这样的问题有好多好多,为了避免类 ...
- 设计模式-软件架构设计七大原则及开闭原则详解
前言 在日常工作中,我们使用Java语言进行业务开发的时候,或多或少的都会涉及到设计模式,而运用好设计模式对于我而言,又是一个比较大的难题.为了解决.克服这个难题,Remi酱特别开了这个博客来记录自己 ...
- 设计模式六大原则之--开闭原则(OCP)
设计模式六大原则之--开闭原则(OCP) 前言 1 描述 2 理解: 3 问题由来: 4 使用LoD的好处: 5 难点: 6 最佳实践: 7 范例: 前言 The Open - Closed Prin ...
- 关于Java面向对象程序设计原则之一——开闭原则的思考与分享
整理日期:2022-05-27 目录 一.开闭原则 二.为什么使用开闭原则 三.如何在程序设计中体现开闭原则 一.开闭原则 开闭原则(Open-Closed Principle, OCP)是指一个软件 ...
- 七大软件设计原则之一 | 开闭原则
公众号「蝉沐风」,你们的赞和评论对我很重要,欢迎大家关注交流 开闭原则是指一个软件实体(模块.类.方法等)应该对扩展开放,对修改关闭 我举一个例子,陀螺是个程序喵,创办了一个生产猫粮的公司--跑码场, ...
最新文章
- ITextSharp使用说明
- 通过FM CO_VB_ORDER_POST更新生产订单的Components数据
- java画图板代码_java学习小总结——画图板制做(附代码)
- 详解C++中的函数调用和下标以及成员访问运算符的重载
- 最小化安装的redhat/centos安装gnome桌面
- python基础之面向对象(一)
- mysql里类似sequence_MySql中实现类似Oracle的Sequence方案
- DBCS和UCS编码相关
- win7系统网络计算机,Win7系统打开局域网没看到其他计算机的修复方法
- 计算机如何安装pdf,pdf虚拟打印机是什么?怎么安装到电脑里
- 高考数学圆锥曲线总结贴+杂题巧解
- 带有动态直方图的亲属关系模型
- Linux USB 摄像头驱动
- 上滑解锁流程 - 安卓R
- Django学习笔记-settings.py详解
- Windows 10 微软官方下载工具
- Java详细讲解OOP面向对象
- 数据治理:元数据及元数据管理策略、方法和技术
- vue style样式变量背景图
- oracle solaris 11用u,前言 - 安装 Oracle Solaris 11 系统
热门文章
- python类创建多个实例是同一个实例_创建一个类的多个实例
- 一元线性回归原理及python简单实现
- php foreach 不等于_PHP性能优化小技巧
- 层次凝聚聚类算法(HAC)
- shiny datatable child row:shiny表格二级子行的展开与折叠
- 使用JSPanda扫描客户端原型污染漏洞
- Raki的读paper小记:Code and Named Entity Recognition in StackOverflow
- Redis缓存相关问题总结
- Linux下PHP开发环境搭建(Apache2.4+PHP7.1+MySQL8.0)
- EHIGH恒高:大话UWB技术之蓝牙定位的烦恼