当前位置: 首页 > news >正文

软件设计模式原则(二)开闭原则

继续讲解第二个重要的设计模式原则——开闭原则~

一.定义

        开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。

归纳总结如下:

  • 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则。
  • 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
  • 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
  • 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
  • 所谓对扩展开放:指的是我们系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能。
  • 所谓对修改关闭:指的是系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的,使用者使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相应修改。

二.描述

开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性~

  • 对软件测试的影响
  • 可以提高代码的可复用性
  • 可以提高软件的可维护性

三.案例

举个简单的例子,假设你的女票(使用方)有一天收到了你送给她的礼物——这礼物有可能是情书,也有可能是手工书~则实现的代码如下:

//礼物类基类
class gift{String type;
}
class Letter extends gift{Letter(){super.type="Letter";}
}class Handwork extends gift{Handwork(){super.type="Handwork";}
}//使用方类,也就是接收方类
class girlfriend{public void drawShape(gift g) {if (g.type == "Letter")getLetter(g);else if (g.type == "Handwork")getHandwork(g);}public void getLetter(gift r) {System.out.println("收到的礼物是情书!");}public void getHandwork(gift r) {System.out.println("收到的礼物是手工书!");}
}public class Main {public static void main(String[] args) {girlfriend hyh = new girlfriend();hyh.drawShape(new Letter());hyh.drawShape(new Handwork());}
}

 这时加入礼物种类添加了一种类型——奢侈品,则对代码的修改如下:

//礼物类基类
class gift{String type;
}
class Letter extends gift{Letter(){super.type="Letter";}
}class Handwork extends gift{Handwork(){super.type="Handwork";}
}
class luxury extends gift{luxury(){super.type="luxury";}
}//使用方类,也就是接收方类
class girlfriend{public void getgift(gift g) {if (g.type == "Letter")getLetter(g);else if (g.type == "Handwork")getHandwork(g);else if (g.type == "Luxury")getLuxury(g);}public void getLetter(gift r) {System.out.println("收到的礼物是情书!");}public void getHandwork(gift r) {System.out.println("收到的礼物是手工书!");}public void getLuxury(gift r) {System.out.println("收到的礼物是奢侈品!");}
}public class Main {public static void main(String[] args) {girlfriend hyh = new girlfriend();hyh.getgift(new Letter());hyh.getgift(new Handwork());hyh.getgift(new luxury());}
}

此时不难发现,不仅修改了提供方(gift类)的代码,也修改了使用方(girlfriend类)的代码,即违反了所谓的开闭原则~(对修改关闭)

 

         也就是说,当发生变更时,提供方是允许修改的,而使用方则不允许,这就是所谓的【对扩展开放,对修改关闭】。

做出如下修改,即可避免:

/****/
//gift类,基类
abstract class gift {//声明为一个抽象类~String type;public abstract void get();//抽象方法
}class Letter extends gift {Letter() {super.type ="Letter";}//重点在于不同的类内部具体实现所谓的方法——即重写@Overridepublic void get() {System.out.println("收到的礼物是情书~");}
}class Handwork extends gift {Handwork() {super.type =" Handwork";}//重点在于不同的类内部具体实现所谓的方法——即重写@Overridepublic void get() {System.out.println("收到的礼物是手工书~");}
}class girlfriend {public void getgift(gift g) {g.get();}
}public class Main {public static void main(String[] args) {girlfriend hyh = new girlfriend();hyh.getgift(new Letter());hyh.getgift(new Handwork());}
}

此时我们想要再添加奢侈品Luxury类,只需要修改提供方即可,不需要修改使用方的代码:

/****/
//gift类,基类
abstract class gift {//声明为一个抽象类~String type;public abstract void get();//抽象方法
}class Letter extends gift {Letter() {super.type ="Letter";}//重点在于不同的类内部具体实现所谓的方法——即重写@Overridepublic void get() {System.out.println("收到的礼物是情书~");}
}class Handwork extends gift {Handwork() {super.type =" Handwork";}//重点在于不同的类内部具体实现所谓的方法——即重写@Overridepublic void get() {System.out.println("收到的礼物是手工书~");}
}
class Luxury extends gift {Luxury() {super.type ="Luxury";}//重点在于不同的类内部具体实现所谓的方法——即重写@Overridepublic void get() {System.out.println("收到的礼物是奢侈品~");}
}class girlfriend {public void getgift(gift g) {g.get();}
}public class Main {public static void main(String[] args) {girlfriend hyh = new girlfriend();hyh.getgift(new Letter());hyh.getgift(new Handwork());hyh.getgift(new Luxury());}
}

 做个总结——牢记对扩展开放,对修改关闭~

(某种意义上,也可以作为【多态】的示例~)

在20世纪90年代,开闭原则被广泛的重新定义由于抽象化接口的使用,在这中间实现可以被改变,多种实现可以被创建,并且多态化的替换不同的实现。

相比梅耶的使用方式,多态开闭原则的定义倡导对抽象基类的继承。接口规约可以通过继承来重用,但是实现不必重用。已存在的接口对于修改是封闭的,并且新的实现必须,至少,实现那个接口。

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • [论文阅读]PV-RCNN++
  • 三国志14信息查询小程序(历史武将信息一览)制作更新过程06-复现小程序
  • <sa8650>qcxser 之 QCarCam 6.X API介绍 (第一部分)
  • MySQL复习总结(二):进阶篇(索引)
  • vue中插槽slot
  • 数字IC后端实现 |TSMC 12nm 与TSMC 28nm Metal Stack的区别
  • C++(Qt)软件调试---下载和安装最新版Windbg(16)
  • 华为H12-831题库
  • 地表水与地下水耦合丨基于QSWATMOD的SWAT-MODFLOW模拟丨模型率定丨案例分析
  • java RMI 技术介绍和实践
  • Redis 的几种集群对比
  • Vue2打包自定义文件命名规则CDN部署前端项目
  • pandas教程:Data Transformation 数据变换、删除和替换
  • C++ set map 的模拟实现
  • 蓝桥杯算法竞赛系列第十章·nSum问题的代码框架
  • canvas绘制圆角头像
  • JavaScript中的对象个人分享
  • ViewService——一种保证客户端与服务端同步的方法
  • Web设计流程优化:网页效果图设计新思路
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 爱情 北京女病人
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 中文输入法与React文本输入框的问题与解决方案
  • 第二十章:异步和文件I/O.(二十三)
  • ​2020 年大前端技术趋势解读
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • #QT(智能家居界面-界面切换)
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (四)opengl函数加载和错误处理
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET的微型Web框架 Nancy
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .NET连接数据库方式
  • .ui文件相关
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • @PostConstruct 注解的方法用于资源的初始化
  • [ vulhub漏洞复现篇 ] JBOSS AS 4.x以下反序列化远程代码执行漏洞CVE-2017-7504
  • [<MySQL优化总结>]
  • [<事务专题>]
  • [100天算法】-不同路径 III(day 73)
  • [20150321]索引空块的问题.txt
  • [20170705]diff比较执行结果的内容.txt
  • [android学习笔记]学习jni编程
  • [C# 开发技巧]实现属于自己的截图工具
  • [C++]spdlog学习
  • [codevs1288] 埃及分数
  • [CSS]浮动
  • [c语言]小课堂 day2
  • [ERROR]-Error: failure: repodata/filelists.xml.gz from addons: [Errno 256] No more mirrors to try.
  • [ffmpeg] aac 音频编码