设计原则
设计原则的逻辑
软件构建目标
- 改动
- 理解
- 复用
以下的原则并非都是正交的,各个原则之间甚至还有可能冲突,这就要求我们必须找到一个合适的点,合理利用这些原则。同时,这些原则也并非金科玉律,每条原则都有其所适用的范围,记住,软件工程没有银弹。
SOLID设计原则
SRP:单一职责原则
任何一个软件模块都应只对某一类行为负责,修改一个类的原因应该只有一个
主要讨论的是函数与类的关系,当这个类需要做过多事情的时候,也就是出现了很多不相关的函数时,就需要分解这个类
OCP:开闭原则
设计良好的软件应该容易扩展,而禁止修改
- 将旧代码的修改量降低至最小,限制变化的范围
该原则要求在添加新功能时不需要修改代码。但是这条原则真的很容易做到吗?在繁杂的业务代码中,大部分情况下,业务发生变更,业务代码必须要进行修改。这就要求我们编写的代码可以适应未来的情况,可根据需求软编码的方式来变更业务逻辑。
依赖方向的控制
通过接口来反转组件之间的依赖关系,使得高阶组件不会因低阶组件被修改而受到影响
信息隐藏
通过中间层使高层组件不过度依赖低层组件的内部细节
LSP:里氏替换原则
一个软件实体如果使用的是一个基类的话,那么它一定也可以使用其子类,而且它根本不能察觉出基类对象和子类对象的区别
animal.run();
// ↓
cat.run();
如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度
- 是一个指导接口与其实现方式的设计原则
ISP:接口隔离原则
对模块来说,跟它无关的接口一旦发生变更,应该不能影响到该模块,不应该强迫客户依赖于它们不用的方法
使用多个专门的接口比使用单一的总接口要好
- 软件设计如果依赖了它并不需要的东西,会带来麻烦
DIP:依赖反转原则
高层模块不应该依赖于低层模块,二者都应该依赖于抽象 抽象不应该依赖于细节,细节应该依赖于抽象。
当然某些情况下抽象必须依赖于细节,比如Object中对String的依赖
想要设计一个灵活的系统,则就应多引用抽象类型,而非具体实现。这么做的原因是接口相比实现更为稳定
主要关注的是系统中那些经常变动的
组合聚合原则
继承体系中 父类的变化也会影响到子类 所以能用组合聚合就不要用继承
DRY dont repat youself
如果多次遇到同样的问题,就应该抽象出一个共同的解决方法,不要重复开发同样的功能
- 完全相同
- 算法相同
违反这个原则常被称为WET(Write everything twice)
YAGNI you ain't gonna need it
指的是你自以为有用的功能,实际上都是用不到的。不要考虑的过于长远
要在设计里规划,不要在代码体现
某种程度上来说,这个原则跟DRY有一定的冲突
Rule of Three
- 第一次使用时,编写它
- 第二次使用时,复制它
- 第三次使用时,就需要进行封装了
是DRY和YAGNI的折中之道。计算机科学中,最常见的就是做取舍了。
KISS keep it simple and stupid
保持简单。并非指实现上的简单,更多地是指让产品(代码)给用户用起来感觉很简单。
POLA 最小惊奇原则
- 遵循常识 不要违反常识性认知