UML之轻松入门(4)-OCP做一个上进的厨子

在上一章节,我们讨论了面向对象设计(OOD)5大特性之一的SRP原则。这一节,我们来看另一重要的原则:OCP原则(开放-闭合原则)。

Software entity should be open for extension, but closed for modification 

上节回顾:

1.UML之轻松入门(1)-类图(附:java Comparable接口与Comparator接口用法)

http://blog.csdn.net/woyunowuyuda/article/details/38981647

2.UML之轻松入门(2)-掌握Junit,让我们的开发更高效

http://blog.csdn.net/woyunowuyuda/article/details/39029689

3.UML之轻松入门(3)-SRP做好厨子,让别人编程去吧

http://blog.csdn.net/woyunowuyuda/article/details/39032305

上节我们说一个厨子要满足SRP原则,做好自己的本职工作,我们可以通过继承和接口两种方式实现。但是现在又出现了一个新的问题:本来这个厨子在学校主学川菜专业,然后在湖南找了一份工作,不得不学习湘菜。学就学呗,谁知顶头上司又是广东人,还得学做粤菜。如果对于一上一节定义的Cooker类来说,今天加一个方法,明天再加一个方法,后天发现某个方法不实用了,再删掉。这样,程序显得杂乱无章。不仅没有效率而且很容易出错。为了解决这类问题,我们想到了OCP原则,即一个软件实体(类,模块,函数等)应当为扩展而开放,又为修改而封闭。如何理解这句话呢,我们拿一个最常见的例子:几乎每个人都有一部手机,可能是安卓的也可能是苹果的。你可以无限制的安装新的软件(只要你的内存够大)。如果你想你的壁纸呢,需要你来修改安卓的源代码吗?完全不用,你只需要再安装一个壁纸就OK。这就是我们所说的OCP原则。为我们的扩展而开放,然而你无需改变模块本身,只需要改变模块的周边环境即可。

下面我们依然拿厨子开刀(是对厨师行业的尊敬),在代码层理解OCP原则:

毕业之后只会川菜(这里原谅我用拼音表示),如今他想学习湘菜和粤菜,是直接在这个类上添加方法吗?显然,这样不利于类的扩展和修改。因此我们可以这样来定义:

首先我们定义一个接口CookSkill,里面有cook方法。然后每一个新学习的烹饪技巧都要实现CookSkill这个接口。那么我们扩展的时候就无需改变Cooker以及CookSkill或其他菜系的代码,只需要添加一个类即可。这样我们就满足了OCP原则。

现在都是考驾照的热潮,这个厨师也弄了一个。好嘛,考完驾照发现自己没车,只好找朋友借个车开开。我们可以这么定义:

也就是说这个Cooker引用了Firend的drive方法。但我们发现Firend类的改变或多或少的会影响Cooker类(也许是参数,也许是名称,也许是返回值等),这时候我们说这两个类的耦合性太高了。并不符合OCP原则。此时,我们可以这么来修改:

这时,我们发现Fiend类和Cooker类的关联没那么紧密了,而且我们还可以用一个单元测试实现DriveSkill接口来完成Cooker的测试,而脱离Firend类的束缚。这样我们就满足了OCP的为了修改而封闭的原则。

我们可以总结一下:

1.什么时候该考虑OCP原则

a.当你的模块存在扩展时应考虑OCP原则,提供新的功能

          b.当两个类的耦合度太高时应考虑OCP原则,保证重要模块的稳定性

2.如何满足OCP原则

使用抽象如接口即可满足OCP原则。在功能扩展方面,定义一个接口来接受新的功能。在模块保护方面,定义一个接口来减少之间的耦合。

3.OCP原则和其他原则之间的关系

开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。因此,针对开闭原则的实现方法,一直都有面向对象设计的大师费尽心机,研究开闭原则的实现方式。后面要提到的里氏代换原则(LSP)、依赖倒转原则(DIP)、接口隔离原则(ISP)以及抽象类(Abstract Class)、接口(Interace)等等,都可以看作是开闭原则的实现方法。

时间: 2024-10-11 08:45:02

UML之轻松入门(4)-OCP做一个上进的厨子的相关文章

UML之轻松入门(3)-SRP做好厨子,让别人编程去吧

一个厨子可以做出一手好菜,也许他是新东方毕业的或者是祖传秘方.你让他做上一桌佳肴那是简单.快乐而又高效的,然而让他编程就会成为一种苦恼并且让人想不通的一件事.也许这个比喻不是很恰当,但是对于每个类来说,他们就像一个一个的actor,也许是厨子也许是司机,他们应该关注于自己的领域,这样会更加高效而且简明.源于这一思想,我们发现了SRP这个原则,即:单一职责原则. There should never be more than one reason for a class to change  既然

UML之轻松入门(2)-掌握Junit,让我们的开发更高效

使用UML不仅可以形象化的表达我们的程序思想,而且可以帮助我们提高程序的质量.一个杂乱无章的程序让维护者望而生畏,其成本也可想而知.在面向程序设计(OOD)中有5条原则是帮助我们设计一个高效.简洁的程序:1.单一职责原则(SRP) 2.开放-闭合原则(OCP) 3.Liskov替换原则(LSP) 4.依存关系倒置原则(DIP) 5.接口隔离原则(ISP).然而这5个原则不是本节讨论的重点,我们将从一个更简单基础的部分入手-JUnit. 想象一下如果程序中每增加一个功能或修改一些代码,都需要整个程

UML之轻松入门(1)-类图

曾经看到过一篇blog,上面探讨了学习UML和学习设计模式的区别,同时提出了学习UML还不如学习设计模式的观点.自我感受是,UML和设计模式在本质上属于完全不同的两个方向.设计模式是一种被反复使用.多数人知晓的.代码设计经验的总结.它可以更容易让人理解而且保证了代码的可靠性,而UML则是一种模型化和可视化的一种语言.可以这么说,设计模式是一种方法,它让我们的代码更有层次感 .而UML则是一种表达,它让我们的代码更加形象化.通过UML我们不必太过关注代码,不必担心客户是否了解相关的语言知识,整体的

【 D3.js 入门系列 --- 5.1 】 做一个带坐标轴和标签的图表

前面几节讲解了图标.坐标轴.比例等等,这一节整合这些内容做一个实用的图表.结果图如下: 代码如下所示: [html] view plain copy <html> <head> <meta charset="utf-8"> <title>Chart</title> </head> <style> .axis path, .axis line{ fill: none; stroke: black; sha

【 D3.js 入门系列 — 3 】 做一个简单的图表!

图1. 柱形图 1. 柱形图 前几章的例子,都是对文字进行处理.本章中将用 D3 做一个简单的柱形图.制作柱形图有很多种方法,比如用 HTML 的 <div> 标签,或在 SVG 上绘制 . SVG ,即可缩放矢量图形(Scalable Vector Graphics),使用 XML 格式定义图形,可在 W3School 学习 SVG 的相关语法,不需要记住所有标签,用的时候再查即可. 先看下面的代码: <script src="http://d3js.org/d3.v3.mi

一只猿:使用flask来做一个小应用

上周 @萍姐 问我如何抓取天猫上面店铺的评分,看了下挺简单的,于是花了点时间写了个Python脚本,加上web.py做成一个web服务,使用起来还不错,今天来看的时候发现当时为了方便直接用web.py开发有点简陋,自己也好久没用flask写过东西了,打算用flask再写一遍,顺便复习下旧的知识,如果你是flask初学者,可以参考这个例子. 提示:博主默认你已经具备了Python的基础知识,已经能够很顺畅的编写一些Python脚本,否则接下来你会比较难看懂. 旧版 这里先给出旧版本的一些使用截图,

Swift轻松入门——基本语法介绍和详细地Demo讲解(利用WebView打开百度、新浪等网页)

本文主要分为两个部分,第一部分介绍Swift的基本语法,第二部分讲解一个利用WebView来打开百度.sina等网页的小demo,如果对swift的语法不感兴趣的同学可以直接跳到第二部分来感受下Swift的魅力-(本文的demo源码已上传至github:https://github.com/iOSGeek0829/XSurfing) 一.Swift常用语法 Swift是Apple去年推出的一门新的语言,基于C和Objective-C,而没有C的一些兼容约束,它采用了安全的编程模式和添加现代的功能

UML建模快速入门00 Outline

Preface UML建模,其重要性不言而喻,本人虽然大学期间就早已知其大名,无奈因各种因素总是拿起又放下,未能持续研究,几经断断续续,一直未持续深入读完一本书.最近越发觉得逆向工程(由代码生成UML)在日常整理中的重要性及方便性,便又捡起书本,觉得应该好好看看,边看边画,对很多概念又有了较深入的理解,对以前模糊的概念更加明晰些了.说实在的,这次拿起书本来看,主要有两个原因:一是觉得UML建模确实应该作为码工具备的一个技能,二是为了提升下逼格. 为了记录个人历经的路程,后续将推出系列快速入门读书

JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)

本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对象只能通过特定的接口访问,这也是面向接口编程思想的一部分. 封装是面向对象编程里非常重要的一部分,让我们来看看没有封装的代码是什么样的: 1 function Dog(){ 2 this.hairColor = '白色';//string 3 this.breed = '贵宾';//string 4 this