[读书笔记] 敏捷软件开发:原则、模式与实践

关于面向对象编程的一些理解,这本书主要看六大原则的部分,书中关于设计模式的内容由于之前的那本《设计模式与游戏完美开发》已经很好的讲解了游戏开发领域的应用,所以不多关注。

面向对象的六大原则

单一职责原则SRP:一个类应该只有一个发生变化的原因,如果你能够想到多余一个的动机去改变一个类,那么这个类就具有多于一个的职责。

public interface Modem {// 连接管理public void Dial(string pno);public void Hangup();// 数据通信public void Send(char c);public char Recv();
}

上述代码一个调制解调器所具有的功能,在接口中显示出连接管理和数据通信两个职责。但这目前还不是需要分离职责的理由,如果应用程序的变化会影响对方,那么是应该被分离的;反之变化总是导致两个职责同时变化,那实际上是不必分离的。

public interface DataChannel {// 数据通信public void Send(char c);public char Recv();
}
public interface Connection {// 连接管理public void Dial(string pno);public void Hangup();
}
public class ModemImplementation {
}

尽管ModemImplementation类会混杂DataChannel和Connection,这并不是我们希望的,但对于其他部分来说,通过接口分离我们已经解耦了概念,而这个类除了Main需要知道,谁也不需要知道它的存在。

开闭原则OCP:软件实体(类、模块、函数等)应该是可以拓展的,但是不可修改。如果正确的应用OCP,那么在进行改动时,只需要添加新的代码,而不是改动已有的代码。
拓展和修改看似是冲突的,如何在不改动模块代码的情况下更改它的行为呢?答案就是抽象。由于模块依赖于一个固定的抽象体,所以它对于更改可以是封闭的。同时,通过从这个抽象体派生,可以拓展次模块的行为。遵循OCP的开发过程是困难的,我们很难保证能够预测到变化的发生,如果我们决定接受重构,那么重构的时间来的越早对项目是越有利的。

里氏替换原则LSP,子类必须能够替换掉他们的基类

public class Shape {public static void DrawShape(Shape s) {if (s.type == ShapeType.square)(s as Square).Draw();else if (s.type == ShapeType.circle)(s as Circle).Draw();}
}
public class Circle: Shape{}
public class Square: Shape{}

上述代码典型的违反了OCP,它必须知道Shape类每个可能的派生类,并且每次创建一个从Shape类派生的新类时都必须要更改它。但是从本质上看,开发者采用重写Draw()的方式,以致于子类无法替换Shape(),违反了LSP,这个违法又迫使DrawShape()违反了OCP。LSP是使得OCP成为可能的主要原则之一,正事子类型的可替换性才使得使用基类型表示的模块在无需修改的情况下就可以拓展。

依赖倒置原则DIP:高层次模块不应该依赖于低层次模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
在这里插入图片描述
上述启发规则对于某些稳定的类是不太合理的,有些类直接依赖于它也不会造成损害,比如String。然而开发者编写的大多数具体类都是不稳定的,为了不直接依赖于这些不稳定的具体类,通过隐藏到抽象接口的后面,以隔离它们的不稳定性。

public class Button {private Lamp lamp;public void Poll() {if (/*some condition*/)lamp.TurnOn();}
}

上述代码Button类直接依赖于Lamp类,当Lamp类发生改变时,Button类会受到影响,这个方案违反了DIP,高层策略没有和低层分离。在这个例子中,背后的抽象是检测用户的开/关指令传给目标对象。至于用什么机制检测,目标对象是什么,都无关紧要。

public interface ButtonServer {public virtual void TurnOff();public virtual void TurnOn(); 
}
public class Lamp : ButtonServer {
}
public class Button {private ButtonServer bs;public void Poll() {if (/*some condition*/)bs.TurnOn();}
}

上述代码就很好的倒置了依赖的方向,Lamp依赖于其他类而不是被其他类依赖,知道如何操纵ButtonServer接口的对象都能够控制Lamp。对于面向过程程序设计所创建出来的依赖关系结构,策略依赖于细节,这是糟糕的,这样策略会受到细节改变的影响。DIP是面向对象设计的标志所在,如果依赖关系不是倒置的,它就是过程化的设计。

接口隔离原则ISP:类与类之间的依赖关系应该建立在最小的接口之上,不应该强迫类依赖并未使用的方法。如果一个客户程序依赖于那些它们不使用的方法,那么这些客户程序就面临着由于这些未使用方法的改变所带来的变更。

迪米特原则LoD:也称为最少知识原则,一个对象应当对其他对象有最少的了解

public class Computer{public void SaveCurrentTask(){ }public void CloseService(){ }public void CloseScreen(){ }public void ClosePower(){ }
}
public class Person{private Computer c;public void ClickCloseButton(){       c.SaveCurrentTask();c.CloseService();c.CloseScreen();c.ClosePower();}
}

上述代码展示了Person想要通过点击按钮关闭Computer的情况,可是由于Computer所有方法都是公开的,Person并不知道电脑关闭的流程,只有Person对Computer关机的流程全部熟悉才能正确的写出ClickCloseButton()这个方法,这违背了LoD。

public class Computer{private void SaveCurrentTask(){ }private void CloseService(){ }private void CloseScreen(){ }private void ClosePower(){ }private void Close(){SaveCurrentTask();CloseService();CloseScreen();ClosePower();}
}
public class Person{private Computer c;public void ClickCloseButton(){c.Close();}
}

改进是明显的,现在Person不需要了解任何Computer的内部逻辑就可以写出ClickCloseButton()方法了。


小结:细心的读者会发现最后一个例子,也是明显的违背DIP,具体类Person依赖于具体类Computer,我们可以想象如果Person还想要通过点击按钮关闭电视、空调等其他机器的时候。但是如果明确了这个项目只需要Person控制电脑,绝不可能出现其他设备呢?难道我们还要再抽象出一个mechine类吗?拒绝不成熟的抽象和抽象本身一样重要

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Caffe-SSD相关源码说明和调试记录

1 对Blob的理解及其操作: Blob是一个四维的数组。维度从高到低分别是: (num_,channels_,height_,width_) 对于图像数据来说就是:图片个数,彩色通道个数,宽,高 Blob中数据是row-…

[游戏策划] 读书笔记

交互式媒体最有趣的地方在于,它让玩家直面问题,思考、尝试各种解决方案,并体验各种解决方案的结果。然后玩家可以回到思考阶段,规划下一步行动。这种反复试错的过程中,玩家的脑海里就会构建出一个互动的世界。 [读书笔…

ECS框架学习

DOTS Unity DOTS是Unity官方基于ECS架构开发的一套包含Burst编辑器和JobSystem的技术栈,它旨在充分利用多核处理器的特点,充分发挥ECS的优势。 安装 Entities、Burst、Jobs、Hybrid Renderer(必选,用于DOTS的渲染相关&#xf…

辅助排序和Mapreduce整体流程

一、辅助排序 需求:先有一个订单数据文件,包含了订单id、商品id、商品价格,要求将订单id正序,商品价格倒序,且生成结果文件个数为订单id的数量,每个结果文件中只要一条该订单最贵商品的数据。 思路&#xf…

[读书笔记] 史玉柱自述:我的营销心得

与下属的关系 从玩家角度设定目标 目标感的设计 论随机性 在前15分钟留住玩家 实际观察玩家对于游戏的翻译反应 好游戏是改出来的 注重细节 决策民主、责任人制度 论简单与复杂的关系 游戏经济中的投放与回收 避免进入降低压力的怪圈 创业初期的股份分配 单个行业…

记一次面试腾讯的奇葩经历

阅读本文大概需要 2.8 分钟。 作者:黄小斜 文章来源:微信公众号【程序员江湖】 ​ 上回说到,我腾讯面试出师不利,简历随即进入备胎池,不过没过多久,转机还是来了。 大概是一周之后,我的电话响起…

foot

码云链接&#xff1a;https://gitee.com/zyyyyyyyyyyy/codes/rcfdzmin4a82v975pl1ko47 效果图&#xff1a; 原网站截图&#xff1a; 源代码&#xff1a; <!DOCTYPE html><html><head><meta charset"UTF-8"><title></title><s…

Taro项目遇到的问题

1. https://taro-ui.aotu.io/#/docs/questions 请在Taro项目根目录找到 config/index.js 文件中的h5项&#xff0c;添加如下&#xff1a; h5: {...esnextModules: [taro-ui] } 2. 原则&#xff1a;少什么就装什么 少了 babel-plugin-transform-decorators-legacy &#xff0c;那…

严重: StandardServer.await: create[localhost:8005]

①看看任务管理器&#xff0c;是否打开了多个Tomcat程序 如果是&#xff0c;关闭其中一个 ②可能是端口冲突 1、将tomcat安装目录下的conf/server.xml中的8005端口号改为其它的端口号。&#xff08;不建议&#xff0c;因为会衍生出其他错误&#xff09; 2、将正在使用的8005端…

java里short,int,long,float,double范围及可写位数

一、取值范围 1、int二进制位数&#xff1a;32 包装类&#xff1a;java.lang.Integer最小值&#xff1a;Integer.MIN_VALUE -2147483648 &#xff08;-2的31次方&#xff09;最大值&#xff1a;Integer.MAX_VALUE 2147483647 &#xff08;2的31次方-1&#xff09;2、short 二…

第六周编程总结

6-1 求两数平方根之和 &#xff08;10 分) 函数fun的功能是&#xff1a;求两数平方根之和&#xff0c;作为函数值返回。例如&#xff1a;输入12和20&#xff0c;输出结果是&#xff1a;y 7.936238。 函数接口定义&#xff1a; double fun (double a, double b); 其中 a和 b是用…

【CH5105】Cookies

也是一道线型动态规划的好题…… 读入每个人的贪婪度之后&#xff0c;对其按照从大到小的顺序排序&#xff0c;定义状态f[i][j]为前i个人&#xff08;排序后&#xff09;分j个饼干的答案&#xff0c;那么答案为f[n][m],考虑状态转移方程。 1、若给第i个人的饼干数大于1 &#x…

sharing-jdbc实现读写分离及分库分表

需求&#xff1a; 分库&#xff1a;按业务线business_id将不同业务线的订单存储在不同的数据库上&#xff1b; 分表&#xff1a;按user_id字段将不同用户的订单存储在不同的表上&#xff0c;为方便直接用非分片字段order_id查询&#xff0c;可使用基因法&#xff1b; 读写分离&…

性能测试学习05_lr(根据接口文档写脚本+参数化)

1、根据接口文档写脚本&#xff0c;函数&#xff08;web_custom_request&#xff09;&#xff0c;完成get&#xff0c;post请求&#xff08;注册&#xff0c;登录&#xff09; 代码&#xff1a; Action() {lr_save_string("请填写你的IP", "IP");//注册/*w…

java 历届试题 合根植物

问题描述w星球的一个种植园&#xff0c;被分成 m * n 个小格子&#xff08;东西方向m行&#xff0c;南北方向n列&#xff09;。每个格子里种了一株合根植物。这种植物有个特点&#xff0c;它的根可能会沿着南北或东西方向伸展&#xff0c;从而与另一个格子的植物合成为一体。如…

(软件项目管理)项目会议纪要模板

备注&#xff1a; 七: 1、报送&#xff1a;把整理好的会议的内容报给上级的相关部门。2、主送&#xff1a;把整理好的会议的内容发放给下级相关部门。3、抄送&#xff1a;把整理好的会议的内容送给相关的同级单位或不相隶属的单位。

EVE-NG安装步骤

首先&#xff0c;需要EVE-NG客户端工具包 1、 1.1部分图 点击next 2、 保持默认全选&#xff0c;点击next 3、 点击install 4、选择I accept the agreement&#xff0c;点击next 5、下一步&#xff0c;继续点击next 6、选定安装位置&#xff0c;不清楚就默认C盘&#x…

第三次实验

Part1: 验证性内容 在循环中使用控制语句continue和break&#xff0c; 其功能区别是什么&#xff1f; continue是停止当前语句的执行&#xff0c;回到第一条语句继续执行&#xff0c;而break是直接结束循环。 在两层嵌套循环中&#xff0c;内层循环中如果出现continue&#xf…

Linux shell 中$() ` `,${},$[] $(()),[ ] (( )) [[ ]]作用与区别

看到几篇博客&#xff0c;觉得写的不错 原文&#xff1a;https://blog.csdn.net/x1269778817/article/details/46535729 和http://blog.zol.com.cn/2322/article_2321763.html $()和 &#xff1a; 在 bash shell 中&#xff0c;$( ) 与 (反引号) 都是用来做命令替换用(c…