关于开闭原则的理解

Unity游戏开发客户端Lua基础 Unity游戏开发客户端面经之 lua 篇 阅读详情

开闭原则:设计一个模块的时候,应当使这个模块可以在不修改原有代码的前提下被扩展。

这个原则是保证系统具有扩展性的基本原则。我理解有几个要点:1、要能够复用;2、扩展时只增加新方法、新类;3、不得不修改代码时,修改的范围必须是局部的、隐藏的;

通常变更有三种方式,一种是横向变更,例如售票系统,原来只能售火车票,现在要可以售机票;第二种是纵向变更,例如在某个流程里插入新活动或跳过活动;第三种是局部修改,就是原有功能的业务规则发生了变化。对于前两种变更比较容易处理,只要在设计时注意抽象,通过接口、继承、override或event即可扩充。对于第三种变更,估计要修改代码了。虽然可以这样分类,但实际上以上三种变更通常是同时发生的、相互交织的。

以库存管理业务单据为例,有出库单、入库单、移库单等。通常单据结构都很相似,包含头表,行表,但个别字段有差异。新增一个单据,先在头表插入一条记录,然后在行表插入若干记录。更新单据时,先更新头表记录,然后清空词单据在行表里的原有记录,再插入新的行表记录,删除单据的过程也非常相似。此外,在单据增删改时要记录日志,在单据提交时,还要修改库存。所有这些操作十分相似,可以抽象出来。

现在要设计一个单据处理通用业务类,负责单据暂存、修改、提交、删除几个基本业务,以及相关的日志和库存操作。

1、分析
   单据操作: Save()/Submit()/Delete()/Log()/ChangeStock()
   相关数据: 头表实体、行表实体集;与日志有关的一些属性;与库存有关的一些属性;插入头表时,要有一个接口获取单据编号;因为插入行表时外键值需要用到头表记录的主键值,所以需要有个接口获取头表主键值,并有一个接口给行表实体的外键赋值;
   可能的变更: 1、将来可能增加审批功能,单据提交后审判通过才改变库存;2、增加新的单据类型;3、将来增加订单管理,那么库存操作除了出入库、还会增加在途转入库存、库存转出在途等功能。
  

2、设计
   方案1、抽象类+子类,只关注操作,不关注数据;
         单据处理类 BillProcess (抽象类):
         公有虚方法 Save()/Submit()/Delete()
         私有虚方法 Log()/ChangeStock()
   扩展:增加审批功能,只需在基类增加新的虚方法Audit,子类实现新的虚方法; 增加单据类型时,只需实现新的单据,增加在途功能,只需修改 ChangeStock;
   评价:此方案虽然很容易扩展,除了需要对ChangeStock作修改外,基本符合开闭原则;但过于抽象,子类需要实现全部操作,基类仅仅起到规范方法名称的作用;此方案的复用度太低;

   方案2、抽象类实现部分模板方法,所有方法都没有参数,抽象类没有任何字段,全部给子类实现;
         单据处理类 BillProcess (抽象类):
         公有虚方法 Save(): 调用IsNew()判断是新增还是更新,如果是新增,设置单据编号SetBillNumber,插入头表InsertHeader,设置行表外键SetBillLineHeaderID;若是更新,则更新头表UpdateHeader,删除行表DeleteLines(),设置行表外键SetBillLineHeaderID,插入行表InsertLines(); 调用 Log();
         公有虚方法 Submit(): 调用 Save(),调用 ChangeStock(); 调用 Log();
         公有虚方法 Delete(): 调用 DeleteHeader(),调用 DeleteLines(); 调用 Log();
        
         保护虚方法 IsNew,判断是新增单据还是更新单据;
         保护虚方法 SetBillNumber,设置头表单据编号;
         保护虚方法 SetBillLineHeaderID, 设置行表所属头表的外键值;
         保护虚方法 InsertHeader/UpdateHeader/DeleteHeader, InsertLines/DeleteLines
         保护虚方法 Log,记录操作员、操作时间、操作类型、单据编号;
         保护虚方法 ChangeStock,改变库存
   扩展:增加审批功能,需在基类增加新的虚方法Audit和NeedAudit虚属性,子类实现新的虚方法和虚属性; 增加单据类型时,只需实现新的单据,增加在途功能,需修改 ChangeStock;
   评价:此方案也很容易扩展,并且基类实现了部分操作,但子类要实现的方法过多,数据库访问方法其实只是表名有点差别,子类却要全部重写;另外子类 ChangeStock 仍要修改;此方案有一定的复用度,但也不高,而且每个子类的ChangeStock都要修改,不满足“开闭原则”的封闭性。

   方案3、一些通用的操作尽量放到 BillProcess,库存操作独立出来成为一个类;抽象出头表实体、行表实体接口;BillProcess可以操作相关数据接口。

         单据头实体接口 IBillHeader:
         BillID 获取或设置主键ID, 如果获取的ID为0,表示为新单据;这样就不需要IsNew()方法了
         BillType 获取单据类型
         BillNumber 获取或设置单据编号, 如果是新单据,BillProcess类可以向单据编号生成器BillNumberGenerator.GetBillNumber(BillType)传入BillType参数,获得单据编号,赋值给此属性;  
         DBField[] 获取实体的字段值数组,便于插入和更新到头表;

         单据行实体接口 IBillLine:
         BillID 设置所属单据头ID
         ProductID 商品ID
         SiteID 库位ID
         Count 商品数量
         DBField[] 获取实体的字段值数组,便于插入到头表;
        
        
         单据处理类 BillProcess (抽象类):
         保护虚属性: 头表名HeaderTableName、行表名LineTableName、头表主键名HeaderTablePKName、行表外键名LineTableFKName、单据类型BillType、头表实体接口IBillHeader、行表集合接口List<IBillLine> BillLines;单据编号 BillNumber;

         公有虚方法 Save(): 根据IBillHeader的BillID判断,如果是新增,调用BillNumberGenerator.GetBillNumber(BillType)获取新单据编号,并把单据号设置到头表实体,通过数据库会话类把头表实体DBField[]插入头表,设置行表外键BillID;若是更新,则数据库会话类用DBField[]更新头表,调用DeleteLines()删除行表记录,设置行表外键IBillLine的BillID,通过数据库会话类把行表实体DBField[]插入行表; 调用 Log();
         公有虚方法 Submit(): 调用 Save(),调用 ChangeStock(); 调用 Log();
         公有虚方法 Delete(): 调用数据库会话类删除头表记录,调用 DeleteLines(); 调用 Log();
         保护虚方法 DeleteLines(): 调用数据库会话类根据LineTableName、LineTableFKName删除行表记录
         保护虚方法 Log,记录操作员、操作时间、操作类型、单据编号;
         保护虚方法 ChangeStock,改变库存, 先调用GenerateStockChanges()把 List<IBillLine> 转为 List<StockChange>, 调用 StockProcess 实现库存操作,便于库存操作扩展
         保护虚方法 GenerateStockChanges(), 把 List<IBillLine> 转为 List<StockChange>;

         单据号生成器 BillNumberGenerator:
         生成单据号 GetBillNumber(BillType)

         库存处理类 StockProcess:
         属性 List<StockChange>, 库存操作数组

         库存改变类 StockChange: 商品ID 库位ID 库存量改变个数 (可扩充增加“在途量改变个数”)

    扩展:增加审批功能和新单据时,方法同方案1;增加在途量,需要扩展StockChange实体类和StockProcess业务类,BillProcess修改 GenerateStockChanges,子类不需要修改.
    评价:基类包含了较多实现,代码复用度高; 子类只需要实现 IBillHeader, IBillLine 和 一些属性即可(这些属性还可以配置到XML文件中,由BillProcess根据BillType读取XML配置信息,这样子类就不必关心这些细节,方便开发); 同时又保留了较强的扩展性,ChangeStock 方法被细化了,在扩充时,要修改的部分也只是底层的、局部的。不足之处是,基类过多地关注了细节,限制了扩展能力和变更的自由度;另外因为是要修改基类,影响的子类较多,需要投入较多的回归测试时间。此方案基本满足开闭原则。

      总体评价,方案3 提供了一个非常强大的业务基类BillProcess,但过于特殊化。目前的支持的流程是 暂存->提交->审批->改变库存,如果再增加一些中间环节,比如审批后增加发货环节,那么就又要修改BillProcess类了。还有,如果不同的单据有不同的流程,那么 BillProcess 就要增加大量属性信息来描述流程。有一种比较理想的设计思路是,把BillProcess变为“业务引擎”,把各种单据的流程配置到文件中,流程引擎读取这些配置信息执行对应的操作。这样增加一个单据或修改一个单据的流程,只需修改配置文件。实际上,这样有点像“依赖倒置”了,用框架来解决问题。


   

   

 

基于ESP32的智能无线广播系统开发博客 通过本项目的开发,我们成功地实现了基于ESP32的智能无线广播系统。该系统不仅具备传统广播的功能,还实现了通过Wi-Fi无线传输音频、实时广播和智能控制等多种先进功能。未来,随着技术的进一步发展,我们还可以扩展更多功能,如智能推荐广播内容、支持语音识别和控制等。希望本项目能够为嵌入式开发人员提供一些思路和参考,帮助大家在实际开发中更好地应用ESP32平台,开发出更加智能和实用的无线广播系统。 阅读详情

相关推荐

如何利用VS2017创建一个简单的窗口

#如何利用VS2017创建一个简单的窗口 1、新建->Windows桌面向导 2、应用程序类型->桌面应用程序,点击确定 3、点击调试->开始调试 可建立如下图的窗口 4、可以在生成的项目文件的中找到windows17_2的应用程序,打开界面如下: 注:新建空白项目也可以,注意在解决方案资源器中添加.cpp文件,如源.cpp文件,下载代码见博文 ...

weixin_46894139的博客 2914

六大原则之开闭原则

1. 开闭原则的介绍 开闭原则(Open Closed Principle)是编程中最基础、最重要设计原则 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。 2. 违反开闭原则示例 package com.study; public class Ocp {

小松de博客 2万+

强化学习Q值迭代的几何视角:从策略区域到快速收敛

在强化学习中,Q值迭代是求解最优策略的核心算法,其理论基础建立在贝尔曼不动点定理之上。该算法通过迭代更新Q函数,使其逐步逼近最优值函数。从几何视角看,整个Q函数空间可被视为一个高维流形,每个Q函数对应流形上的一个点,而贝尔曼最优算子则定义了流形上的变换轨迹。理解这一几何结构,特别是由策略超平面划分出的凸多面体区域,对于分析算法的收敛行为至关重要。在实际工程中,传统Q值迭代可能在高维或稀疏奖励环境下收敛缓慢,甚至陷入策略高原。通过引入策略区域缓存与自适应学习率等几何启发方法,可以更高效地导航策略空间,加速策略

weixin_30444111的博客 317

七大原则——开闭原则

开闭原则的定义 开闭原则(Open Closed Principle,OCP)由勃兰特·梅耶(Bertrand Meyer)提出,他在 1988 年的著作《面向对象软件构造》(Object Oriented Software Construction)中提出:软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but c...

m0_37654408的博客 6608

汽车零部件智能装配:C#+YOLOv8实现螺栓漏装检测与齿轮错位识别(附PLC通信与机械臂控制)

YOLOv8:小目标检测的最优解相比YOLOv7,YOLOv8的C2f特征融合网络对小目标(5-10mm螺栓)检测精度提升12%,且推理速度快8%;支持大输入尺寸(不显著增加耗时),可放大螺栓细节;官方提供yolov8n.pt(nano版),在边缘计算盒上能跑40+FPS,满足实时性。C#:工业软件的“兼容性核心”主流PLC(西门子S7-1200/1500)、机械臂(ABB、KUKA)的SDK多基于.NET开发,C#可直接调用,避免跨语言通信延迟;多线程管理成熟(Task。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1146

SAP移动类型

SAP移动类型移动类型定义 移动类型定义

qq_20593197的博客 6201

设计模式的六大基本原则(开闭原则、单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特法则)

设计模式的六大基本原则(开闭原则、单一职责原则、历史替换原则、接口隔离原则、依赖倒置原则、迪米特法则)

聂可以的博客 1万+

PCL CSF布料模拟算法【2026最新版】

CSF布料模拟地面滤波算法的PCL实现,博客长期更新,本文最近更新时间为:2026年10月26日。

点云侠的博客 3917

开闭原则 (Open/Closed Principle, OCP)

开闭原则是面向对象设计中的基本原则之一,通过确保软件实体对扩展开放,对修改关闭,可以提高系统的稳定性、灵活性和可维护性。在实际开发中,遵循开闭原则有助于我们设计出高质量的代码,使系统更加健壮和易于扩展。希望这个博客对你有所帮助。如果你有任何问题或需要进一步的例子,请随时告诉我!

qq_42798343的博客 3355

利用dpabi和restplus提取ROI灰质体积学习笔记

目录前言一、数据准备二、利用dpabi提取ROI灰质体积三、restplus提取ROI灰质体积 前言 我利用SPM/CAT12进行灰质、白质、脑脊液分割之后分别已经得到各自的图像文件,在全脑水平已经做了统计分析。如果还想要进一步进行ROI的统计分析或者与量表等临床资料做相关分析,就需要提取ROI灰质体积。几个月没动过这数据了,突然心血来潮想学一下如何提取ROI灰质体积,以此篇博客记录我的提取ROI灰质体积学习过程。提取ROI灰质体积的方法及软件有许多种,本人尝试了dpabi和restplus。 一、数据准备

weixin_52073820的博客 9222

基于Python的异步爬虫实战:高效抓取同花顺概念板块数据

本文将详细介绍如何使用Python最新异步爬虫技术(requests-html+aiohttp+selenium)高效抓取同花顺概念板块数据。内容涵盖:反爬机制破解、动态页面渲染处理、数据解析存储等完整流程,并提供可复用的高性能爬虫代码实现。高性能:异步并发处理,QPS可达50+高可用:完善的异常处理机制可扩展:支持分布式部署增加历史数据回溯功能集成机器学习识别验证码构建实时数据推送系统。

2201_76125261的博客 1534

【设计原则】开闭原则

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

码农桶子哥的博客 1353

ABAP 7.40 新语法介绍系列之六:使用 FILTER 关键字对 ABAP 内表进行过滤

笔者之前写过的关于 ABAP 740 新语法的文章:本文介绍另一个新的关键字:FILTER.FILTER 是 ABAP 740 中引入的一个关键字,用于简化数据操作,它能够将内部表(Internal Table)中的数据按特定的条件进行过滤,并生成一个新的内部表。FILTER 的引入旨在使代码更加现代化和高效,尤其是在面对大量数据需要过滤的情况下。传统上,开发人员可能需要使用 LOOP AT 结合条件判断来实现,但使用 FILTER 关键字后,代码显得更加简洁且易于维护。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1167

深入理解设计原则之开闭原则(OCP)【软件架构设计】

开闭原则(Open Closed Principle, OCP),又称为对扩展开放、对修改关闭原则。开闭原则即是SOLID原则中最难理解、最难掌握的,又是最有用的。之所以说开闭原则最难理解,是因为“怎样的代码改动才被定义为扩展?怎样代码的改动才被定义为修改?怎样才算满足或违反开闭原则?修改代码就一定意味着违反开闭原则吗?等问题都比较难理解。之所以说开闭原则最难掌握,是因为如何做到对扩展开放,对修改关闭?如何在项目中灵活应用开闭原则避免在追求高扩展的同时影响代码的可读性等问题都很难掌握。

weixin_30197685的博客 2340

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

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

文章目录1.前言2.概念3.作用4.实现方法3.实例 1.前言 在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。首先介绍下什么是开闭原则? 2.概念 开闭原则(Open closed principle,OCP)由勃兰特·梅耶(Bertrand Meyer)提出,软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,bu

2949

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

我理解的开闭原则 Open-Closed Principle

在开发新的功能时我们常常会提到开闭原则,即一个类对于拓展是开放的,对于修改是关闭的,"open for extension but closed for modification"。有人可能会问拓展一个类的功能不就是要修改这个类吗?那开闭原则怎么会成立呢? 我的理解是当我们需要给一个类添加新的功能的时候,最好的办法不是直接修改这个类的代码,应该考虑用一个新类去实现新的功能。最终的效果是一...

qq_20694641的博客 503

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

理解OCP开闭原则和DIP依赖倒置原则

这样子就可以实现,当我去在调用时,总结使用多态传递相关的子类引用,那么就可以达到后期增加业务时,加代码,总结创建类,实现接口即可,不会去修改原有代码。但上面代码还不是很成功,当用户类型增加,那么工厂类是不是又要继续去switch...case了呢,此时我们只是提出传统写法是违反OCP开闭原则的。首先以一个例子引入,传统方法,不使用遵循OCP开闭原则的弊端。来改进代码,使其符合 OCP。那么如何去解决这个问题呢。通过引入一个抽象接口。

weixin_63855746的博客 313

谈谈开闭原则(OCP)的翻译问题和我的理解

OCP(Open-Close Principle):软件实体应该可以扩展,但不可以修改。 一开始看到开闭原则时,我觉得这个说法非常扯淡,还不是一般的扯淡。不能修改这个可能吗?人的认知和推动软件发展的硬件都是在进步的,你却在说不能修改。 而且从这个理论的提出时间:1988到今天2012-08-11,24年了有哪个软件做到了这个原则?! 但在后续的学习中发现很多文章都在说,而且我想我

blue_morning的专栏 1212

面试被问到如何理解开闭原则

但凡是面试中遇到问设计模式的时候,一定要提想法设法的提设计原则,阐述设计原则在开发中应用的重要性,对代码性能,系统拓展性的重要性,相信按照这篇文章阐述一番,面试官一定能发现你高深设计思想。 开闭原则是SOLID中最难理解、最难掌握,同时也是最有用的一条原则。 之所以说这条原则难理解,那是因为: 怎样的代码改动才被定义为‘扩展’? 怎样的代码改动才被定义为‘修改’? 怎么才算满足或违反‘开闭原则’? 修改代码就一定意味着违反‘开闭原则’吗? 等等这些问题,都比较难理解。 之所以说这条原则难掌握,那是因为:

斯巴达人的博客 279

开闭原则理解

今天看一个教程,里面提到了开闭原则,搜索了好几个网友的帖子,总结经验如下: 定义:一个软件模块如类、模块和函数应该对扩展开放,对修改关闭。 开闭原则强调了用抽象构建框架、用实现扩展细节。通常为了满足开闭原则,我们应该尽可能的面向抽象编程。 优点:提高软件系统的可复用性及可维护性。 具体例子:现在我们有一个课程接口,它有很多具体课程的实现类,我们可以通过具体的实现类来获取具体课程价格。 public...

元曦的博客 1511

开闭原则的理解与实践

开闭原则,简而言之,就是软件中的对象(类、模块、函数等)应该对于扩展是开放的,对于修改是封闭的。这一原则由Bertrand Meyer在1988年提出,它要求我们在设计软件时,应使软件实体能够在不修改其源代码的前提下进行扩展。换句话说,当需求发生变化时,我们应该通过添加新的代码来满足新的需求,而不是修改现有的代码。这一原则的核心思想在于,将软件实体的变化部分与不变部分相分离,通过抽象和封装来实现软件的灵活性和可扩展性。

huaqianzkh的专栏 1464

OCA、OCP、OCM理解

可能大家知道OCA、OCP、OCM的关系是一个比一个难考,一个比一个含金量高,但是你知道具体的考试科目、考试方式、就业形势区别吗?不知道的话这篇通俗易懂的文章会让你一目了然。   区别一:含金量   ■OCA:数据库专业人员踏上Oracle数据库认证之途的第一步   表示具备Oracle数据库管理的基础知识。   ■OCP:数据库专业人员掌握Oracle专项技术的行业认可证明,证明持证者能

wolf09311的专栏 1093

开闭原则-快速理解

定义 一个软件实体入,如类模块和函数应该对扩展开放,对修改关闭。我们应该把注意力集中在扩展开放和修改关闭这两个行为上。 扩展开放:可以扩展实现的细节,增加新的功能。 修改关闭:不修改原先定义的规则,尽量不修改源代码。 同时准寻这两个行为,即为遵循开闭原则。 开闭原则是面向对象设计中最基础的设计原则。 就比如:一个公司的上班时间是8小时,但是去上班的时间可以任意,早去上班早下班,晚去晚下班,只要满8...

BREATH57的博客 661

对开闭原则的一些理解

[size=large] 从开始学习J2EE开始,就一再地被灌输开闭原则多么核心多么重要,编码也两年了,回顾一下众多的设计模式,蓦然发现开闭原则几乎是所有设计模式的抽象总结 :o 。 一、依赖倒置模式(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的...

碧血丹心 270

开闭原则的理解

开闭原则,“软件实体应当对扩展开放,对修改关闭”,是要达到一个状态,而要达到这个状态,就需要在写代码的过程中要想到和做到。。。 提倡开闭原则,其目的是我们在编写代码的时候就要考虑到每个功能模块的潜在的变化的可能性,尽可能的写简短单一功能并且复用性强的模块。 只有在写代码的时候注意到了这些,在重构或者变更的时候,才能做到“对扩展开放,对修改关闭”。 引用一段百度百科中关于开闭原则实现的一段

mezheng的专栏 1283

php 开闭原则,深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP_javascript技巧...

前言本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第2篇,开闭原则OCP(The Open/Closed Principle )。开闭原则的描述是:Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.软...

weixin_32865039的博客 203
上一篇: 模拟星空的MFC源代码_Sky.RAR,下载地址:http://download.youkuaiyun.com/source/332601
下一篇: 基于AxWebBrowser实现完美的标签式浏览器,下载地址:http://download.youkuaiyun.com/source/337096
AppFramework
博客等级 码龄19年 61粉丝 29原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值