架构整洁之道(四)-三种编程范式
一、三种编程范式简介
-
结构化编程
对程序的直接转移做了限制。
-
面向对象编程
对程序的间接转移做了限制。
-
函数式编程
对变量的赋值做了限制。
-
怎么理解?请往下看。
三种编程范式都是为了解决某些问题而出现的。合理利用,能够让代码更好维护。
三种编程范式,都是为了限制。 这些年我们从编程范式中学到的,不是要做什么,而是不能做什么。
二、结构化编程编程范式
-
什么是结构化编程?
结构化程序设计(英语:Structured programming),一种编程典范。它采用子程序、程序码区块(英语:block structures)、for循环以及while循环等结构,来取代传统的 goto。
-
结构化编程对写代码的影响。
1.结构化编程限制了goto的使用。
2.结构化编程促使我们先将程序递归降解成一系列可以被证明的小函数。然后尝试证明这些小函数是错误的。如果不能证明,则说明当前程序足够正确。
-
结构化编程提升了程序的复用性。
1.我们使用c语言实现一个功能,如果不使用goto语句,基本就属于结构化编程了。
2.因为使用了一系列可以被证明的小函数,提升了复用性。
-
理解对程序的直接转移做了限制。
其实就是指禁止了goto的使用。
之前的程序能够直接跳转到任何位置,现在对于这种做法进行了限制,只能使用if-else/循环 来做。
-
结构化编程对架构设计的启发
1.尽量使用小函数。
2.设计的时候要先拆分问题。弄成一个个好用的模块,函数。来组合起来解决问题。
3.保证代码的可降解性。就是要代码始终是容易拆成几部分的。
/* 比如这样的代码也要避免 虽然没有调用goto,但是也很难拆分。 尤其是多层嵌套,而且代码量特别大的时候。 */ int xxxfunction() { if(condition1 == OK) { if(condition2 == OK && !condition3) { if(condition4) { //do something return 0; } else { return -1; } } } } /* 举个例子 可能可以这样写, 因为这样好拆。避免了多层嵌套。 */ int xxxfunction() { /*block1*/ if(!condition1) { return -1; } /*block2*/ bool bNeedDoIt = (condition2 == OK && ! condition3); if(!bNeedDoIt) { return -1; } /*block3*/ if(!condition4) { return -1; } /*do something*/ return 0; }
三、面向对象编程范式
-
什么是面向对象编程。
还没有找到定义。存在多种说法。
1.面向对象是把数据和方法写到一起的。<----这种说法没有意义。C语言一个模块内把数据和函数写在一起,也是一样的。
2.面向对应有封装继承和多态三大特性。<----其实C语言也可以实现类似的特性。
那什么是面向对象编程呢?
对于架构而言,面向对象编程就是使用多态手段,对函数指针的使用做了限制。
-
为什么要对函数指针的使用作出限制呢?
《架构整洁之道》:
在一个程序中,所有的程序员都必须遵循某一个共同的约定来使用函数指针。
只要有一个程序员没有遵守这些约定,就会出现难以定位和消除的bug。
记得我之前刚刚学习了《unix编程艺术》的分离原则的时候。觉得作者说的非常有道理。然后迅速把策略和机制分离的方法运用到了工作中,当时,我在一个不是很长的流程中,添加了七个函数指针。
代码一写完我就觉得不对劲,按照这个写法,估计用不了多久,不说别人,我自己就要被绕晕了。
-
如何理解是对函数的间接转移做了限制?
而使用了函数指针之后:
可能就是 1->8->3 了。
-
而面向对象的编程范式,就是对这种方式的程序转移做了限制。
比如,构造函数,析构函数,等多态的操作。
-
面向对象编程对架构设计的启发。
函数指针,是模块之间解耦合的重要工具。
很多时候,如果不使用函数指针,模块之间就必须耦合起来,形成难以维护的代码。
但是,肆意的使用函数指针。整个程序更是会变得没人看得懂。就像是到处使用goto语句一样。跳来跳去,反复横跳。你永远找不到程序怎么跑的。
在设计的时候,一定要想好,到底哪些地方可能要多态的实现,只按照固定的约定使用函数指针。
四、函数式编程范式
-
什么是函数式编程?
我自己的理解,就是类似数学里面的f(x)=x^2.这样的。每个函数都是参数输入和返回值输出。整个程序由这些函数组成。程序中变量是不可变得。
-
特点
最大特点是变量不可变。也就是变量被初始化之后,就不再改变了。
就不会出现竞争,死锁,并发更新的问题。
-
靠谱吗?变量不变能完成功能吗?
如果不考虑CPU效率的情况下,是可行的。
比如:
计算银行某个客户的存款余额。
可以把客户的取款操作都记录下来。
然后每次查余额的时候,根据初始化的值,还有存取款的记录,算出一个余额来返回。就结束了。
不需要修改任何变量。
-
如何理解对变量的赋值做了限制?
C语言的变量值是可以随时改变的。
变量的改变经常导致出乎意料的bug。要是问题总是偶然复现,就会更加难以解决。
比如:
手机铃声响起的时候,表示有来电。这时候,程序员将手机状态设置成 ringing 状态(赋值操作)。然后用户这个时候点个接听,就可以和远端通话。
而程序员可能没考虑到闹钟也会让手机铃声响起,设置ringing 状态,这个变量的赋值操作,可能会影响到闹钟的使用。
禁止对变量的赋值,是减少bug的大利器。
-
函数式编程对架构的设计的启发。
对于我们嵌入式的编程而言,不考虑CPU效率是不可能的。
但是函数式编程却给了我启发,变量的赋值要被严格的控制。
1.将程序,模块,变量的赋值控制在一小部分代码中,将减少bug的出现。
在C语言中,随便定义一个全局变量,然后就随便赋值。或者是封装一个设置值的函数,然后满世界的调用。这些情况都要慎重考虑。
2.将不用变的模块和需要改变的模块隔离开来。
或许不是所有的模块,组件都不变,但是可以隔离出来某些和业务流程比较远的组件。完美的利用函数式编程的优势。
3.不要使用表达式,使用函数。
如果使用了表达式,要考虑能否使用一个函数替代。而且要思考这个函数属于哪个模块。否则,这种算法可能造成了模块间的耦合。为之后的开发造成不方便。
五、参考文献
《架构整洁之道》
《重构:改善既有代码艺术》
《unix编程艺术》
百度