设计原则与思想

最近在学习设计模式和设计原则的课程,整理一些心得体会吧。

初衷

最功利的目标,应对面试

面试造火箭,进去拧螺丝,大环境就是这样。

写出高质量的代码

在面对垃圾代码方面,与作者同感。目前在公司里维护的代码写的跟屎一样,层级繁琐,逻辑混乱,恨不得全部重构。

提高复杂代码的设计和开发能力。

从个人的编程经验来看,面对复杂架构时,大局观尤其重要。如何分层分模块,如何设计类与类之间的关系,如何做到高内聚低耦合等等问题,都需要在掌握一定的设计模式和编程思想的知识后,才能够游刃有余地进行处理。

更方便地读源码,学框架

这点感同身受,学好设计模式,夯实基本功,只有基本功足够扎实,面对优秀的源码时才能快速读懂其内容,并且get到其中的精髓。

为职场发展做铺垫

纯管理的路线不太适合自己,还是比较倾向半技术半管理的发展方向。充分掌握和发挥设计模式的作用,有助于提升项目的整体代码质量,方便开发和维护工作;同时也能将高价值的内容分享给他人,更好地考察新人和培养新人。

代码质量的评价标准

可维护性(maintainability)

修改、添加和删除功能能够轻松完成,bug容易修复。

可读性(readability)

符合代码规范,命名合理,注释详细、函数内容合理、模块划分清晰。

可拓展性(extensibility)

添加新功能时,不需要改动大量代码。

灵活性(flexibility)

代码易拓展,代码易复用,一套代码适用多种场景。

简洁性(simplicity)

代码简单,逻辑清晰。
“思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。”

可复用性(reusability)

面向对象特性(继承、多态),设计原则(单一职责原则),重构技巧(解耦、高内聚、模块化)。可复用性是很多设计原则、思想、模式所要达到的最终结果。

可测试性(testability)

从侧面反映了代码质量的好坏。

编程方法论

面向对象

面向对象是目前主流的编程风格(编程范式),以类或对象作为组织代码的基本单元,其四大特性(封装、抽象、继承、多态)可以实现很多复杂的设计思路,是很多设计原则和设计模式实现的基础。

设计原则

设计原则是代码设计方面的一些经验总结,常见的有SOLID原则、DRY原则、KISS原则、YAGNI原则和LOD原则。

设计模式

设计模式是针对软件开发中常遇到的问题,总结出来的一套解决方案或者设计思路,大部分设计模式主要解决的是代码的可拓展性问题。

编程规范

编程规范主要解决的是代码的可读性问题,例如如何给类、函数、变量命名,如何写代码注释,函数不宜过长,参数不能过多等等内容。

重构

重构是软件开发中极其重要的环节,持续重构是保持代码质量不下降的有效手段。针对原先设计满足不了新需求的问题,就需要进行重构。重构时需要使用到面向对象、设计原则、设计模式和编程规范这些理论。

设计原则与思想

面向对象

1、面向对象分析

针对框架、类库、组件等非业务系统的开发,其中一个比较大的难点就是,需求一般比较抽象和模糊,需要做合理的取舍和权衡,把抽象的问题具体化,最终产出清晰的、可落地的需求定义。

2、面向对象设计

划分职责并确定有哪些类;定义类的属性和方法;定义类与类之间的交互关系;将类组装起来并提供执行入口。

3、面向对象编程

一种编程风格(编程范式),以类和对象作为组织代码的基本单元,拥有封装、抽象、继承、多态四大特性。

4、封装、抽象、继承、多态

4.1 封装
(1)定义:类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或数据。
(2)作用:能够隐藏和保护数据,实现访问控制,提升安全性,通过有限的方法提升类的易用性。

4.2 抽象
(1)定义:一种关注功能点而不关注实现的设计思路,通常使用“协议”、“抽象类”和函数等特性来隐藏方法的具体实现。
(2)作用:隐藏具体实现细节,提升代码可拓展性。

4.3 继承
(1)定义:用来表示类与类之间“is a”的关系。
(2)作用:代码复用,关联关系紧密的类。
(3)缺点:层次过深、过于复杂的继承关系会严重影响代码的可维护性(使用组合、协议、委托的方式能够解决该问题并同时保留继承的优点)。

4.4 多态
(1)定义:子类替换父类,在实际代码运行过程中,调用子类的方法实现。
(2)作用:提升代码的可拓展性和复用性

5、抽象类与接口类

越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能在不破坏原有代码设计的情况下灵活应对。

5.1 抽象类
(1)抽象类是对成员变量和方法的抽象,反映的是类与类之间“is a”的关系。
(2)抽象类不允许被实例化,只能被继承。
(3)抽象类主要解决代码复用的问题。

5.2 接口类
(1)接口类是对方法的抽象,反映的是类与类之间“behave like”的关系。
(2)接口类主要解决解耦问题,隔离了接口和具体的实现,提升了代码的拓展性。
(3)其实接口类更准确的说法应该是协议,例如Objective-C语言中的protocol。

设计原则

1、“单一职责”原则(SOLID原则part1)

1.1 概念
一个类或模块只负责完成单一功能。

1.2 注意事项
不同的应用场景、不同阶段的需求背景和不同的业务层面,对同一个类或模块的职责是否单一,可能产生不同的评判结果。

2、“对扩展开发,对修改关闭”原则(SOLID原则part2)

2.1 概念
在添加新功能时,应尽量在已有代码基础上扩展代码(新增模块、类、方法),而非修改已有代码。

2.2 注意事项
时刻具备扩展意识、抽象意识和封装意识。写代码时多花点时间思考未来可能出现哪些需求变更,事先留好扩展点,以便在未来以最小的代码改动来完成新功能。

3、“里式替换”原则(SOLID原则part3)

3.1 概念
子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变和原有程序的正确性。

3.2 注意事项
该原则用于指导子类的设计,父类定义了函数的“约定”(协议),子类可以改变函数内部的实现逻辑,但是不能改变函数原有的“约定”,包括输入、输出、异常处理等等内容。

4、“接口隔离”原则(SOLID原则part4)

4.1 概念
调用者或实现者不应该被强迫依赖其不需要的接口。接口可理解为一组API接口集合、单个API接口或函数或“协议”。

4.2 注意事项
与“单一职责”原则不同,“接口隔离”原则更侧重于接口的设计,从调用者或实现者的角度来评判接口的职责是否单一。

5、“依赖反转”原则(SOLID原则part5)

5.1 概念
该原则用于指导框架层面的设计,高层模块不依赖低层模块,它们共同依赖同一个抽象,抽象不依赖具体实现细节,具体实现细节依赖抽象。

5.2 注意事项
控制反转:用于指导框架设计的思想,使用框架之后,整个程序的执行流程通过框架来控制,流程的控制权从程序员“反转”到框架。
依赖注入:不通过new的方式在类内部创建依赖类的对象,而是将依赖类的对象在外部创建好之后,通过构造函数、函数参数等方式传递(注入)给当前类来使用。

6、“KISS”原则

6.1 概念
(1)“Keep it simple and stupid”,代码保持简洁。
(2)最终目的是提升代码的可读性和可维护性。

6.2 注意事项
(1)尽量不要使用同事可能不懂的技术来实现代码。
(2)尽量不要重复造轮子,要善用已有的工具类库。
(3)不要过度优化。

7、“DRY”原则

7.1 概念
(1)“Don’t repeat yourself”,代码不要重复。
(2)最终目的是提升代码的复用性。

7.2 注意事项
(1)代码逻辑重复时,要根据功能语义来判断代码是否重复。
(2)代码逻辑不重复时,功能语义可能相同。

8、“LOD”原则(迪米特法则)

8.1 概念
(1)不该有直接依赖关系的类(模块)之间,不要有依赖;有依赖关系的类(模块)之间,尽量只依赖必要的接口(协议)。
(2)最终目的是降低类(模块)之间的耦合度,做到“高内聚,低耦合”,提升代码的可读性和可维护性。

8.2 注意事项
(1)高内聚:相近的功能尽量放到同一个类(模块)中。
(2)低耦合:类(模块)之间的依赖关系要简单清晰。