点击上方“java大数据修炼之道”,选择“设为星标”

优质文章, 第一时间送达

来源 | https://www.cnblogs.com/three-fighter/p/12353205.html

什么是开闭原则?

开闭原则的定义:

Software entities like classes,modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。)

在开发软件的过程中,因为变化 、升级和维护等原因需要对软件原有的代码进行修改,可能会将错误引入原本已经测试过的旧代码中,破坏原有的系统,因此,当软件需求变化时,我们应尽量运用扩展的方式来实现变化,而不是修改原来的代码。

开闭原则详解

以书店销售书籍为例:

6-1:书店售书类图

书籍接口IBook:

public interface IBook {//书籍有名称public String getName();//书籍有售价public int getPrice();//书籍有作者public String getAuthor();
}

小说类NovelBook: 是一个具体的实现类,是所有小说书籍的总称。

public class NovelBook implements IBook {//书籍名称private String name;//书籍的价格private int price;//书籍的作者private String author;//通过构造函数传递书籍数据public NovelBook(String _name,int _price,String _author){
this.name = _name;this.price = _price;this.author = _author;}//获得作者是谁public String getAuthor() {return this.author;}//书籍叫什么名字public String getName() {return this.name;}//获得书籍的价格public int getPrice() {return this.price;}
}

书店售书类:

public class BookStore {private final static ArrayList bookList = new ArrayList();//static静态模块初始化数据,实际项目中一般是由持久层完成static{bookList.add(new NovelBook("天龙八部",3200,"金庸"));bookList.add(new NovelBook("巴黎圣母院",5600,"雨果"));bookList.add(new NovelBook("悲惨世界",3500,"雨果"));bookList.add(new NovelBook("金*梅",4300,"兰陵笑笑生"));}//模拟书店买书public static void main(String[] args) {NumberFormat formatter = NumberFormat.getCurrencyInstance();formatter.setMaximumFractionDigits(2);System.out.println("-----------书店卖出去的书籍记录如下:-----------");for(IBook book:bookList){System.out.println("书籍名称:" + book.getName()+"\t书籍作者:" +book.getAuthor()+"\t书籍价格:"+ formatter.format (book.getPrice()/100.0)+"元");}}
}

运行结果:

-----------------书店卖出去的书籍记录如下:--------------书籍名称:天龙八部  书籍作者:金庸    书籍价格:¥25.60元书籍名称:巴黎圣母院 书籍作者:雨果    书籍价格:¥50.40元书籍名称:悲惨世界  书籍作者:雨果    书籍价格:¥28.00元书籍名称:金*梅    书籍作者:兰陵笑笑生 书籍价格:¥38.70元

现在新的需求来了,受移动互联网发展的影响,书店必须打折来维持书店的生存。所有40元以上的书籍9折销售,其他的8折销售。

该如何实现这个变化,有三种方式:

● 修改接口

在IBook上新增加一个方法getOffPrice(),专门用于进行打折处理,所有的实现类实现该方法。但是这样修改的后果就是,实现类NovelBook要修改,BookStore中的main方法也修改,同时IBook作为接口应该是稳定且可靠的,不应该经常发生变化,否则接口作为契约的作用就失去了效能。因此,该方案否定。

● 修改实现类

修改NovelBook类中的方法,直接在getPrice()中实现打折处理。该方法在项目有明确的章程(团队内约束)或优良的架构设计时,是一个非常优秀的方法,但是该方法还是有缺陷的。例如采购书籍人员也是要看价格的,由于该方法已经实现了打折处理价格,因此采购人员看到的也是打折后的价格,会因信息不对称而出现决策失误的情况。因此,该方案也不是一个最优的方案。

● 通过扩展实现变化

增加一个子类OffNovelBook,覆写getPrice方法,高层次的模块(也就是static静态模块区)通过OffNovelBook类产生新的对象,完成业务变化对系统的最小化开发。好办法,修改也少,风险也小,修改后的类图如图6-2所示。

6-2:书店售书类图

打折销售的小说类OffNovelBook: 仅仅覆写了getPrice方法,通过扩展完成了新增加的业务。

public class OffNovelBook extends NovelBook {public OffNovelBook(String _name,int _price,String _author){super(_name,_price,_author);}//覆写销售价格@Overridepublic int getPrice(){//原价int selfPrice = super.getPrice();int offPrice=0;if(selfPrice>4000){  //原价大于40元,则打9折offPrice = selfPrice * 90 /100;}else{offPrice = selfPrice * 80 /100;}return offPrice;}
}

店打折销售类: 需要依赖子类,稍作修改。

public class BookStore {private final static ArrayList bookList = new ArrayList();//static静态模块初始化数据,实际项目中一般是由持久层完成static{bookList.add(new OffNovelBook("天龙八部",3200,"金庸"));bookList.add(new OffNovelBook("巴黎圣母院",5600,"雨果"));bookList.add(new OffNovelBook("悲惨世界",3500,"雨果"));bookList.add(new OffNovelBook("金*梅",4300,"兰陵笑笑生"));}//模拟书店买书public static void main(String[] args) {NumberFormat formatter = NumberFormat.getCurrencyInstance();formatter.setMaximumFractionDigits(2);System.out.println("-----------书店卖出去的书籍记录如下:-----------");for(IBook book:bookList){System.out.println("书籍名称:" + book.getName()+"\t书籍作者:" + book.getAuthor()+ "\t书籍价格:" + formatter.format (book.getPrice()/100.0)+"元");}}
}

运行结果:

----------------------书店卖出去的书籍记录如下:---------------------书籍名称:天龙八部  书籍作者:金庸    书籍价格:¥25.60元书籍名称:巴黎圣母院 书籍作者:雨果    书籍价格:¥50.40元书籍名称:悲惨世界  书籍作者:雨果    书籍价格:¥28.00元书籍名称:金*梅   书籍作者:兰陵笑笑生 书籍价格:¥38.70元

开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变 更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

为什么要采用开闭原则?

开闭原则是最基础的一个原则,其余的原则都是开闭原则的具体形态, 也就是说其余五个原则就是指导设计的工具和方法。换一个角度 来理解,依照Java语言的称谓,开闭原则是抽象类,其他五大原则是具体的实现类。

可通过以下几个方面来理解其重要性:

1、开闭原则对测试的影响

以上面提到的书店售书为例,IBook接口写完了,实现类NovelBook也写好了,需要写一个测试类进行测试。

小说类的单元测试:

public class NovelBookTest extends TestCase {private String name = "平凡的世界";private int price = 6000;private String author = "路遥";private IBook novelBook = new NovelBook(name,price,author);//测试getPrice方法public void testGetPrice() {//原价销售,根据输入和输出的值是否相等进行断言super.assertEquals(this.price, this.novelBook.getPrice());}
}

一般一个方法的测试方法一般不少于3种——首先是正常的业务逻辑要保证测试到,其次是边界条件要测试到,然后是异常要测试到,比较重要的方法的测试方法甚至有十多种,而且单元测试是对类的测试,类中的方法耦合是允许的,在这样的条件下,如果再想着通过修改一个方法或多个方法代码来完成变化,是很难做到的。

如果用扩展的方式,新增加的类,新增加的测试方法,只要保证新增加类是正确的就可以了。

2、开闭原则可以提高复用性

在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来的,而不是在一个类中独立实现一个业务逻辑。只有这样代码才可以复用,粒度越小,被复用的可能性就越大。那为什么要复用呢?减少代码量,避免相同的逻辑分散在多个角落,避免日后的维护人员为了修改一个微小的缺陷或增加新功能而要在整个项目中到处查找相关的代码。那怎么才能提高复用率呢?缩小逻辑粒度,直到一个逻辑不可再拆分为止。

2、开闭原则可以提高可维护性

一款软件投产后,维护人员的工作不仅仅是对数据进行维护,还可能要对程序进行扩展,维护人员最愿意做的事情就是扩展一个类,而不是修改一个类。

3、 面向对象开发的要求

万物皆对象,我们需要把所有的事物都抽象成对象,然后针对对象进行操作,但是万物皆运动,有运动就有变化,有变化就要有策略去应对,怎么快速应对呢?这就需要在设计之初考虑到所有可能变化的因素,然后留下接口,等待“可能”转变为“现实”。

如何应用开闭原则?

开闭原则是一个比较抽象的原则,前面5个原则是对开闭原则的具体解释,但是开闭原则并不局限于这么多,它更多地像一句口号,一个目标,而没有提出具体的实现办法。这就需要自己在工作中领会精神,总结办法。

1. 抽象约束

通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放,其包含三层含义:第一,通过接口或抽象类约束扩展,对扩展进行边 界限定,不允许出现在接口或抽象类中不存在的public方法;第二,参数类型、引用对象尽 量使用接口或者抽象类,而不是实现类;第三,抽象层尽量保持稳定,一旦确定即不允许修改。

2. 元数据(metadata)控制模块行为

尽量使用元数据来控制程序的行为,减少重复开发。什么是元数据?用来描述环境和数据的数据,通俗地说就是 配置参数,参数可以从文件中获得,也可以从数据库中获得。举个非常简单的例子,login方 法中提供了这样的逻辑:先检查IP地址是否在允许访问的列表中,然后再决定是否需要到数 据库中验证密码(,该行为就是一个 典型的元数据控制模块行为的例子。

3. 制定项目章程

在一个团队中,建立项目章程是非常重要的,因为章程中指定了所有人员都必须遵守的 约定,对项目来说,约定优于配置。

4. 封装变化

对变化的封装包含两层含义:第一,将相同的变化封装到一个接口或抽象类中;第二, 将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或 抽象类中。封装变化,也就是受保护的变化(protected variations),找出预计有变化或不稳 定的点,为这些变化点创建稳定的接口,准确地讲是封装可能发生的变化,一旦预测到 或“第六感”发觉有变化,就可以进行封装,23个设计模式都是从各个不同的角度对变化进行 封装的。

 需要各种编程学习资源的朋友(不论是java、C、Android、python、HTML、ios等等语言、bootstrap、node.js、 angularjs、spring、Springboot、Springcloud、SpringMVC等等各种框架, redis, 多线程高并发编程、JVM、mysql、oracle数据库资源 、大数据全套开发学习资源, maven、svn、idea工具类视频等等等资源, 我们统统都有, 5个网盘. 将近10T学习资源, 总有你想要的) , 更多精品优质学习资源尽在微信公众号【java大数据修炼之道】

推荐学习路线:

1、java学习路线全攻略(资料、视频、源码、项目实战)

2、【史上最强实战项目合集】java项目20套 +完整版java学习视频

推荐面试技巧:

1、面试时被质疑学历、年龄该怎么办?

2、如何应对面试官问你职业规划问题

3、面试的时候问:你的期望薪资多少?怎么谈?

4、面试官问,你有什么问题需要问我的吗?

5、给培训出来的Java程序员的一点建议,教你如何找工作

最近热文推荐:

1、单怼多线程,60道面试题,你能答上几个?(附答案)

2、String 也能做性能优化,我只能说牛逼!

3、用 float 存储金额,老板说损失从工资里扣!

4、这12张手绘图,让我彻底搞懂了微服务架构!

5、Java中当对象不再使用时,不赋值为null会导致什么后果 ?

6、SQL 查询总是先执行SELECT语句吗?你们都错了!

7、看完这篇Redis缓存三大问题,保你能和面试官互扯。

注:加群要求 微信学习交流群:

1、想学习JAVA这一门技术, 对JAVA感兴趣零基础,想从事JAVA工作的。
2、工作1-5年,感觉自己技术不行,想提升的
3、如果没有工作经验,但基础非常扎实,想提升自己技术的。
4、还有就是想一起交流学习的。

小编个人微信

(如果你有学习上不懂的问题、需要学习视频资源等;都可长按识别上方二维码添加小编为好友, 我将免费为你提供完整的学习路线和各种视频学习资源)

如果您觉得不错,请别忘了转发、分享、点赞让更多的人去学习, 您的举手之劳,就是对小编最好的支持,非常感谢!

如何您想进技术群交流,关注公众号在后台回复 “加群”,或者 “学习” 即可

著作权归作者所有,欢迎大家投稿 (投稿作者我会在公众号一一署名一并感谢

或者直接微信扫描下方二维码加群,二维码有效期仅有七天,要加群的赶紧上车,失效请加我微信2782278837统一拉群

--完--

—写文不易,你的转发就是对我最大的支持—


看完本文有收获?请转发分享给更多有需要的人

微信公众号|Java_Bigdata_Study

小编微信号|2782278837

关注Java大数据修炼之道公众号,轻松获取海量资源、最新资讯、粉丝福利等等等等

长按识别二维码,即可关注我们

写留言

喜欢就点击下“在看”吧!

【专题系列】设计模式—— 六:开闭原则相关推荐

  1. 【设计模式】开闭原则

    开闭原则 开闭原则是编程中最基础.最重要的设计原则 一个软件实体如类,模块和函数应该对扩展开放**(对提供方),对修改关闭(对使用方)**.用抽象构建框架,用实
现扩展细节. 当软件需要变化时,尽量通 ...

  2. Java设计模式之开闭原则(Open-Closed Principle)

    Software entities like classes, modules and functions should be open for extension but closed for mo ...

  3. 《设计模式》——开闭原则

    一.什么是开闭原则 对修改关闭,对扩展开放.比如有一个书城,售卖书籍有原价,现在要新增一个打折价.那么,一定要保证已有功能不被修改破坏,而是把新功能扩展出来,不要影响原有功能,而是把新功能扩展出来,不 ...

  4. 设计模式之----开闭原则(Open closed principle OCP)的理解

    文章目录 1.前言 2.概念 3.作用 4.实现方法 5.实例 1.前言 在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据原则来开发程序,从而提高软件开 ...

  5. 深入浅出设计模式原则之开闭原则(OCP)

    下面以两个例子来解释开闭原则(程序代码) [按例1]Windows 的桌面主题设计 分析:Windows 的主题是桌面背景图片.窗口颜色和声音等元素的组合.用户可以根据自己的喜爱更换自己的桌面主题,也 ...

  6. 设计模式-02.经典设计原则-第一节-单一职责原则,开闭原则,里式替换,接口隔离【万字长文系列】

    文章目录 设计模式经典设计原则-第一节 单一职责原则(SRP) 如何理解单一职责原则? 如何判断类的职责是否足够单一? 类的职责是否设计得越单一越好? 开闭原则(OCP) 如何理解"对扩展开 ...

  7. 设计模式六大原则(6)——开闭原则

    定义:一个软件实体如类.模块和函数应该对扩展开放,对修改关闭. 问题由来:在软件的生命周期内,因为变化.升级和维护等原因需要对软件原有代码进行修改时,可能会在旧代码中引入错误,也可能会使我们不得不对整 ...

  8. 设计模式-软件架构设计七大原则及开闭原则详解

    前言 在日常工作中,我们使用Java语言进行业务开发的时候,或多或少的都会涉及到设计模式,而运用好设计模式对于我而言,又是一个比较大的难题.为了解决.克服这个难题,Remi酱特别开了这个博客来记录自己 ...

  9. 设计模式六大原则之--开闭原则(OCP)

    设计模式六大原则之--开闭原则(OCP) 前言 1 描述 2 理解: 3 问题由来: 4 使用LoD的好处: 5 难点: 6 最佳实践: 7 范例: 前言 The Open - Closed Prin ...

最新文章

  1. 皮一皮:现在知道公司老说信息完整的重要性...
  2. Java 接口语法_JAVA接口的基本语法
  3. Py之wordcloud:python中非常有趣的词云图wordcloud简介、安装、使用方法、案例应用详细攻略
  4. 创建第一个Django项目
  5. 给字符串对象定义一个repeat功能。当传入一个整数n时,它会返回重复n次字符串的结果。
  6. Struts2上传文件的大小设置
  7. 浅谈bash shell的种类以及linux系统中的profile和bashrc配置文件
  8. android MD5 SHA1
  9. 条件语句和循环语句_总结一下条件语句和循环语句
  10. java之备忘录模式,java设计模式之备忘录模式
  11. Eclipse中Build Workspace 优化
  12. MD5加密不可逆的原因
  13. 傅里叶变换 matlab FFT 函数解析
  14. win7安装网络打印机显示windows无法连接到打印机,出现错误0x00000bcb
  15. Mac中Xcode如何更改编辑器文本字体大小
  16. Windows10修改Users下的用户文件夹名
  17. 如何批量将 bmp 格式图片转换转换为 jpg
  18. 一文看懂ARM Cortex-M处理器
  19. CHIL-ORACLE-创建表
  20. 【数电实验7】Verilog—外星萤火虫

热门文章

  1. 数据结构与算法学习:数组
  2. NETDMIS5.0螺纹孔测量2023
  3. 计算机考试可以用华为m6吗,华为m6可以当笔记本用吗
  4. 手把手教你快速创建一个超高性价比弹性云服务器
  5. 华为鸿蒙系统用久了会卡吗,使用华为鸿蒙系统的手机会越用越卡吗
  6. 深度学习中常用的优化算法
  7. 物联网工程实践日报表
  8. 内网ip和外网ip的联系以及连接过程
  9. 计算机技术基础知识,计算机技术基础知识课件
  10. 购物车(七)-计算商品总价——计算总价-计算属性 数据缓存api-wx.setStorageSync()方法