又是一个没写多少代码,但是却花了半个晚上思考程序OOP结构的夜晚,我发现这是在浪费时间,而且会让你的大脑很累,感觉昏昏沉沉的.所以我痛定思痛,写下下面的一些感悟总结. 不一定对,而且随着时间变化,一些观点也会改变吧.
- OOP不是必要: 当需要实例化多个相同类型的对象时,使用OOP来组织程序是很好的,但当整个程序中只存在一个实例(单例)的时候,面向对象设计得到的收益并不是很大.
- C++不是必要: 使用C语言设计程序,也能通过结构体,宏,将工程分割成一系列小的子目录,文件和函数等方法,体现出模块间继承,组合的关系.宏真的很强大,比C++的template更灵活易用.当然,使用C++你能获得一些更加现代的语言特性.
- 动态分配内存不是必要: 如果变量大小可以在编译期确定(与用户输入无关),可以不动态分配内存,通过宏配置变量,定义为全局变量开到静态区.动态分配内存会增加很多工作量和麻烦(比如管理class内动态分配的数组),并且会牺牲性能,既然编译期可以确定,为什么还要动态分配呢?
- 若非必要,勿增封装: 使用OOP会不由自主地追求封装的完美,但是最终效果与性能其实不会因为你花了大量时间让代码架构变的好看而更好(甚至会更坏,封装性很有可能带来性能上的劣化),抑制自己想要封装的欲望,必要时再抽象封装,适度地封装.刚开始接触一个系统的时候,不可能考虑的非常周全,程序的结构随着开发而不断重构迭代是非常正常的,没有必要在一开始的时候就追求完美的封装性.
最近一直想着一统RISC-V和loogArch指令集的微结构,但是我发现我又一次陷入了思考抽象封装的迷宫中,指令集本来就是和微结构强相关的,指令集很大程度上决定了微结构的设计,我在试图抽象出一个无用的概念. 我意识到之前还有没有想到的一点是:
5.大统一是有代价的: 当手上拿着抽象这一工具,"一统万物"的幻象是那样的迷人,于是我总是忍不住这里那里到处敲敲,不知不觉中,我开始企图统一一切,而没有思考过其中的代价. 在合适的层次进行抽象封装可以统一很多东西,便于复用代码,便于参数化配置,收益大于付出. 但是越是来到更高的层次,越是发现为了求同存异,不得不要做出妥协和让步,给自己带上了一副不必要的镣铐,收益小于了付出. 统一到一定程度就够了,而且有时候你会发现你会抽象出一个无用的概念. 存在即合理,如果他们不叫同一个名字,那么一定存在一定程度的差异.
6.若非必要,勿增泛化: 最近常常使用template,很喜欢用<typename T>
,但其实只有当这个对象在代码中确实需要实例化多个变量类型才需要这样写,否则如果整个文件中只有一种变量类型需要实例化,应当使用using
或者#define
来规定变量类型。泛化太多之后,会导致lsp(例如clangd
)反应不出来,也会给代码增加没有必要的复杂性。
本文采用知识共享署名4.0国际许可协议(CC BY 4.0)进行许可