钻研OO设计模式有一段时间了,可是天生愚笨,总是不得真谛,于是想是不是该跳出来仔细的想一想了呢?为什么需要设计模式?GoF的23设计模式的设计原则是什么呢?在查阅了一些资料后,仿佛有了一些感觉,其实设计模式的原则就是OOD的原则,或者说设计模式是为了达到OOD的远景而提出的,所以正真的想掌握OO的精髓,那么学习设计模式是最好的途径,而想真正掌握设计模式的精髓,那麽就必须好好的理解一下OOD的设计原则,这篇文章关注的只是其中的一个原则--OCP。下面通过引用CSDN上Health King的专栏的一篇我认为比较好的关于OCP原则的文章开始我们的认识OCP之旅吧!
原文链接:http://blog.csdn.net/kxy/archive/2005/06/27/405013.aspx
在继续《设计模式精解》这本书之前,我们来学习些OOD的一些设计原则。这些原则在提高一个系统可维护性的同时,提高这个系统的可复用性他们是一些指导原则,依照这些原则设计,我们就可以有效的提高系统的复用性,同时提高系统的可维护性。
这些OOD原则的一个基石就是“开-闭原则”(Open-Closed Principle OCP)。这个原则最早是由Bertrand Meyer提出,英文的原文是:Software entities should be open for extension,but closed for modification。意思是说,一个软件实体应当对扩展开放,对修改关闭。也就是说,我们在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,换句话说就是,应当可以在不必修改源代码的情况下改变这个模块的行为。
满足OCP的设计给系统带来两个无可比拟的优越性:
----- 通过扩展已有的软件系统,可以提供新的行为以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。
----- 已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。
具有这两个优点的软件系统是一个高层次上实现了复用的系统,也是一个易于维护的系统。那么,我们如何才能做到这个原则呢?不能修改而可以扩展,这个看起来是自相矛盾的。其实这个是可以做到的,按面向对象的说法,这个就是不允许更改系统的抽象层,而允许扩展的是系统的实现层。
解决问题的关键在:抽象化。我们让模块依赖于一个固定的抽象体,这样它就是不可以修改的;同时,通过这个抽象体派生,我们就可以扩展此模块的行为功能。如此,这样设计的程序只通过增加代码来变化而不是通过更改现有代码来变化,前面提到的修改的副作用就没有了。
“开-闭”原则如果从另外一个角度讲述,就是所谓的“对可变性封装原则”(Principle of Encapsulation of Variation, EVP)。讲的是找到一个系统的可变因素,将之封装起来。在我们考虑一个系统的时候,我们不要把关注的焦点放在什么会导致设计发生变化上,而是考虑允许什么发生变化而不让这一变化导致重新设计。也就是说,我们要积极的面对变化,积极的包容变化,而不是逃避。
[SHALL01]将这一思想用一句话总结为:“找到一个系统的可变因素,将它封装起来”,并将它命名为“对可变性的封装原则”。
“对可变性的封装原则”意味者两点:
----- 一种可变性应当被封装到一个对象里面,而不应当散落到代码的很多角落里面。同一种可变性的不同表象意味着同一个继承等级结构中的 具体子类。继承应当被看做是封装变化的方法,而不应当是被认为从一般的对象生成特殊的对象的方法(继承经常被滥用)。
----- 一种可变性不应当与另外一种可变性混合在一起。从具体的类图来看,如果继承结构超过了两层,那么就意味着将两种不同的可变性混合在了一起。
“对可变性的封装原则”从工程的角度说明了如何实现OCP。如果按照这个原则来设计,那么系统就应当是遵守OCP的。但是现实往往是残酷的,我们不可能100%的遵守OCP,但是我们要向这个目标来靠近。设计者要对设计的模块对何种变化封闭做出选择。
好了,上面就是引用的全文了。那麽在实际设计和开发之中,我们该如何重构我们的设计和代码呢?
答案是:抽象(Astraction)、多态(Polymorphism)、继承(Inheritance)、接口(Interface)。利用这些就可以让我们去实践OCP了,这样就会让我们的设计符合OCP,符合该法则便意味着最高等级的复用性(Reusability)和可维护性(Maintainability)。当然我们也有很多的设计模式可以利用来很优美的解决如何封装变化等问题,但是不要忘了,设计模式的基础也是抽象(Astraction)、多态(Polymorphism)、继承(Inheritance)、接口(Interface)啊。还是从最简单开始吧,千里之行,始于足下...
考虑下面某个类的方法: 但是现在每当计价策略发生改变,我们就必须修改Part 的每个子类!
一个更好的思路是采用一个PricePolicy类,通过对其进行继承以提供不同的计价策略,那麽这里就是在运用设计模式里面的策略模式了,解决起来算是很完美了: 看起来我们所做的就是将问题推迟到另一个类中,将“变化”封装在PricePolicy类里面。但是使用该解决方案,我们可通过改变Part对象,在运行期间动态地来设定计价的策略。另一个解决方案是使每个ConcretePart从数据库或属性文件中获取其当前的价格,这样相当于把“变化”封装在了属性文件里面了。
- public double totalPrice(Part[] parts) {
- double total = 0.0;
- for(int i = 0;i
- total += parts[i].getPrice();
- }
- return total;
- }
以上函数的工作是在制订的部件数组中计算各个部件价格的总和。若Part是一个基类或接口且使用了多态,则该类可很容易地来适应新类型的部件,而不必对其进行修改。其将符合OCP
但是在计算总价格时,若财务部颁布主板和内存应使用额外费用,则将如何去做。下列的代码是如何来做的呢?这符合OCP吗?
- public double totalPrice(Part[] parts) {
- double total = 0.0;
- for(int i = 0;i
- if(parts[i] instanceof Motherboard)
- total += (1.45*parts[i].getPrice());
- else if(parts[i] instanceof Memory)
- total += (1.27*parts[i].getPrice());
- else
- total += parts[i].getPrice();
- }
- return total;
- }
当每次财务部提出新的计价策略,我们都不得不要修改totalPrice()方法!这并非“对更改是封闭的”。显然,策略的变更便意味着我们不得不要在一些地方修改代码的,因此不符合OCP,那麽我们该如何去做呢?
为了使用我们第一个版本的totalPrice(),我们可以将计价策略合并到Part的getPrice()方法中。
这里是Part和ConcretePart类的示例:
- public class Part {
- private double basePrice;
- public void setPrice(double price) {
- basePrice = price;
- }
- public double getPrice() {
- return basePrice;
- }
- }
- public class Motherboard extends Part {
- public double getPrice() {
- return 1.45*basePrice;
- }
- }
- public class Memory extends Part {
- public double getPrice() {
- return 1.27*basePrice;
- }
- }
-
但是现在每当计价策略发生改变,我们就必须修改Part 的每个子类!
一个更好的思路是采用一个PricePolicy类,通过对其进行继承以提供不同的计价策略,那麽这里就是在运用设计模式里面的策略模式了,解决起来算是很完美了:
- public class Part {
- private PricePolicy pricePolicy;
- public void setPricePolicy(PricePolicy policy) {
- pricePolicy = policy;
- }
- public void setPrice(double price) {
- pricePolicy.setPrice(price);
- }
- public double getPrice() {
- return pricePolicy.getPrice();
- }
- }
- public class PricePolicy {
- private double basePrice;
- public void setPrice(double price) {
- basePrice = price;
- }
- public double getPrice() {
- return basePrice;
- }
- }
- public class SalePrice extends PricePolicy {
- private double discount;
- public void setDiscount(double discount) {
- this.discount = discount;
- }
- public double getPrice() {
- return basePrice*discount;
- }
- }
-
看起来我们所做的就是将问题推迟到另一个类中,将“变化”封装在PricePolicy类里面。但是使用该解决方案,我们可通过改变Part对象,在运行期间动态地来设定计价的策略。另一个解决方案是使每个ConcretePart从数据库或属性文件中获取其当前的价格,这样相当于把“变化”封装在了属性文件里面了。
分享到:
相关推荐
- SOLID原则:单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则,是面向对象设计的基石。 7. **敏捷开发与面向对象**: - 敏捷开发强调迭代和灵活应对变化,面向对象的特性很好地适应了...
2. **设计原则**:OOD强调设计原则,如单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)和依赖倒置原则(DIP)。这些原则指导开发者创建可维护、可扩展的代码结构。 3. **设计...
1. 面向对象原则:单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)、依赖倒置原则(DIP)是面向对象设计的基石,它们指导我们编写出易于扩展和维护的代码。 2. UML(统一建模...
uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。
本课程是 PHP 进阶系列之 Swoole 入门精讲,系统讲解 Swoole 在 PHP 高性能开发中的应用,涵盖 协程、异步编程、WebSocket、TCP/UDP 通信、任务投递、定时器等核心功能。通过理论解析和实战案例相结合,帮助开发者掌握 Swoole 的基本使用方法及其在高并发场景下的应用。 适用人群: 适合 有一定 PHP 基础的开发者、希望提升后端性能优化能力的工程师,以及 对高并发、异步编程感兴趣的学习者。 能学到什么: 掌握 Swoole 基础——理解 Swoole 的核心概念,如协程、异步编程、事件驱动等。 高并发处理——学习如何使用 Swoole 构建高并发的 Web 服务器、TCP/UDP 服务器。 实战项目经验——通过案例实践,掌握 Swoole 在 WebSocket、消息队列、微服务等场景的应用。 阅读建议: 建议先掌握 PHP 基础,了解 HTTP 服务器和并发处理相关概念。学习过程中,结合 官方文档和实际项目 进行实践,加深理解,逐步提升 Swoole 开发能力。
matlab齿轮-轴-轴承系统含间隙非线性动力学 基于matlab的齿轮-轴-轴承系统的含间隙非线性动力学模型,根据牛顿第二定律,建立齿轮系统啮合的非线性动力学方程,同时也主要应用修正Capone模型的滑动轴承无量纲化雷诺方程,利用这些方程推到公式建模;用MATLAB求解画出位移-速度图像,从而得到系统在不同转速下的混沌特性,分析齿轮-滑动轴承系统的动态特性 程序已调通,可直接运行 ,关键词:Matlab;齿轮-轴-轴承系统;含间隙非线性动力学;牛顿第二定律;动力学方程;修正Capone模型;无量纲化雷诺方程;位移-速度图像;混沌特性;动态特性。,基于Matlab的齿轮-轴-轴承系统非线性动力学建模与混沌特性分析
2024年移动应用隐私安全观测报告.pdf
本电影评论网站管理员和用户。管理员功能有个人中心,用户管理,电影类别管理,电影信息管理,留言板管理,论坛交流,系统管理等。用户可以对电影进行评论。因而具有一定的实用性。本站是一个B/S模式系统,采用SSM框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得电影评论网站管理工作系统化、规范化。 本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高电影评论网站管理效率。 关键词:电影评论网站;SSM框架;MYSQL数据库 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2 2.1 MYSQL数据库 2 2.2 B/S结构 3 2.3 Spring Boot框架简介 4 3系统分析 4 3.1可行性分析 4 3.1.1技术可行性 4 3.1.2经济可行性 5 3.1.3操作可行性 5 3.2系统性能分析 5 3.2.1 系统安全性 5 3.2.2 数据完整性 6 3.3系统界面分析 6 3.4系统流程和逻辑 7 4系统概要设计 8 4.1概述 8 4.2系统结构 9 4.
2023-04-06-项目笔记-第四百三十六阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.434局变量的作用域_434- 2025-03-13
基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动 1100027-基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动、阈值设置、LCD1602、超阈值报警、proteus) 功能描述: 基于STM32F103C8单片机实现的智能流速、流量,流量计设计 实现的功能是通过信号发生器模拟齿轮传感器,检测流量的大小,同时计算流过液体的总容量 可以设置最大流过的总容量,当超过设定值后通过蜂鸣器与LED灯指示 当没有超过则启动水泵控制电路带动液体流动 1、流速检测 2、流量统计 3、阈值显示与设置(通过按键实现阈值的调节或清零) 4、水泵启动 5、超阈值报警 有哪些资料: 1、仿真工程文件 2、PCB工程文件 3、原理图工程文件 4、源代码 ,核心关键词: 基于STM32的流量计; 智能流速流量监测; 水泵报警系统; 阈值设置; LCD1602; 超阈值报警; Proteus仿真; STM32F103C8单片机; 齿轮传感器; 信号发生器; 流量统计; 蜂鸣器与LED灯指示; 水泵控制电路。,基于STM32的智能流量监测与报警系统(阈值可调、流速与流量监
(灰度场景下的平面、海底、船、受害者)图像分类数据集【已标注,约1100张数据】 数据经过预处理,可以直接作为分类网络输入使用 分类个数【4】:平面、海底、船、受害者【具体查看json文件】 划分了训练集、测试集。存放各自的同一类数据图片。如果想可视化数据集,可以运行资源中的show脚本。 图像分类、分割网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 计算机视觉完整项目:https://blog.csdn.net/qq_44886601/category_12816068.html
arkime无geo下的oui文件
人脸识别项目实战
人脸识别项目实战
CAD 2025 二次开发dll
人脸识别项目源码实战
c语言学习
基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性 降低电流脉动,和误差 基于扩张状态观测器eso补偿的三矢量模型预测控制 ,基于扩张状态观测器; 扰动补偿; 权重因子调节; 电流预测控制; 参数鲁棒性; 电流脉动降低; 误差降低; 三矢量模型预测控制,基于鲁棒性增强和扰动补偿的电流预测控制方法
c语言学习