Mar...">
美文网首页
<实现模式>阅读笔记 --理论

<实现模式>阅读笔记 --理论

作者: 乖张的小乌龟 | 来源:发表于2019-01-10 12:00 被阅读29次

    "任何一个傻瓜都能写出机器能懂的代码.好的程序员应该写出人能懂得代码."
    by <重构:改善既有代码的设计> Martin Fowler

    第一章 -简介

    用代码沟通的几个步骤:

    1. 必须在编程时保持清醒.
      迈向沟通的第一步就是让自己慢下来,弄明白自己究竟思考了些什么,不再假装自己是在凭本能编程.
    2. 承认他人的重要性.
      编程很少会是一个人与一台机器之间孤独的交流,我们应该学会关心其他人,而这需要练习.
    3. 公布自己的想法,并且承认别人也有权和我一样存在.
      更有意识的编程,为他人编程,而不仅为自己编程.

    第二章 -模式

    绝大多数程序都遵循一组简单的法则:

    1. 更多时候,程序是在被阅读,而不是被编写.
    2. 没有"完工"一说.修改程序的投入会远大于最初编写程序的投入.
    3. 程序都由一组基本的语句和控制流概念组合而成.
    4. 程序的阅读者需要理解程序--既从细节上,也从概念上.有时他们从细节开始,逐渐理解概念;有时他们从概念开始,逐渐理解细节.

    模式便是基于以上这些共性之上的.
    比如说,每个程序员都必须决定该如何进行迭代遍历.在思考如何写出循环的时候,大部分领域问题暂时都被抛之脑后了,留下的就是纯技术问题:这个循环应该容易懂,容易编写,容易验证,容易修改,而且高效.
    让你操心的这一系列事情,就是模式的起源.上面列出的这些约束,会影响程序中每个循环编写的方式.可以预见到,这样的约束会不断的重现,这也正是模式成为模式成为原因:它其实是关于约束的模式.

    有好几种合理的方式可以写成一个循环,它们分别暗含着对这些约束的不同优先级排序:如果性能更重要,你可能采用这种方式来写循环;如果容易修改更重要,你可能就会使用另一种方式来写循环.

    每个模式都代表着一种对约束进行相对优先级排序的观点.每个模式都带着一个解决方案的种子,模式在抽象的原则和具体的实践之间架起了一座桥梁.

    模式彼此协作.
    建议你用for循环,又引出"如何给循环变量命名"的问题.我们不尝试把所有事情塞进一个模式里.还有另一个模式专门讲"如何给变量命名"的话题.

    使用模式有时会让你感到束手束脚,但确实可以帮你节省时间和精力.
    打个比方,就好像铺床这件小事,如果每次都必须思考每个步骤怎么做,找出正确的顺序,那就会比习惯成自然的做法耗费更多的精力.正是因为有一组铺床的模式,这件事才得以大大简化.若果床正好在墙边,或者床单太小,你就需要根据情况调整策略,但整体来说还是遵循固定模式来铺床,这样你的脑子就可以用来思考更有意思,更有必要的东西.
    编程也一样,当模式成为习惯之后,我很开心地发现自己不必再为"如何写一个循环"而展开讨论了.如果整个团队都对一个模式不满,那么他们可以讨论引入新的模式.

    没有任何一组模式能够适用于所有的情况.
    盲目效仿别人的风格,永远都不如思考和实践自己的风格并在团队中讨论交流来得有效.

    模式最大的作用就是帮助人们做决定.

    第三章 -一种编程理论

    就算是再巨细靡遗的模式列表,也不可能涵盖编程中遇到的每一种情况.你免不了(甚至常常)会遭遇到这种场景:上穷碧落,也找不到对应的现成解决方案.这也是学习编程理论的原因之一.原因之二则是那种知晓如何去做,为何去做之后所带来的胸有成竹.

    每一个模式都承载着一点点理论.但编程理论在实际编程中存在一些更加深广的影响力,远不是孤立的模式所能概括的.本章会讲述这些贯穿于编程中的横切概念,它们分为两类:价值观原则.

    价值观是编程过程中的统一支配性主题.
    珍视与其他人沟通的重要性,把代码中多于的复杂性去掉,并保持开放的心态,这才是我工作状态的最佳表现.这些价值观--沟通,简单,灵活--影响了我在编程时所做的每一个决策.

    原则不像上面价值观那样意义深远,不过每一项原则都在许多模式中得以体现.
    价值观有普遍的意义,但往往难以直接应用;模式虽然可以直接使用,却是针对特定情景;原则在价值观和模式之间搭建了桥梁.
    我早已发现,在那种没有模式可以应用或是两个相互排斥的模式可以同等应用的场合,如果把编程原则弄清楚,对解决疑难会是一件好事.在面对不确定性的时候,对原则的理解让我可以"无中生有"创造出一些东西,同时能和其他的实践保持一致,而且结果一般不错.

    价值观,原则,模式,这三者元素互为补充,组成了一种稳定的开发方式.

    3.1 价值观

    有三个价值观与卓越的编程血脉相连:

    1. 沟通
    2. 简单
    3. 灵活

    虽然上面三者有时会冲突,但更多时候相得益彰.最优秀的程序员会为未来的扩展留下充分的选择,不包含不相关的元素,容易阅读,容易理解.

    3.1.1 沟通

    Knuth所提出的文学编程理论促使我把注意力放到沟通上来:程序应该读起来像一本书一样.它需要有情节和韵律,句子间应该有优雅的小小跌宕起伏.

    每次遇到难以解释清楚的逻辑,重新把它写一遍都要比解释这段代码为何难以理解容易得多.

    在编程时注重沟通还有一个很明显的经济学基础:软件的绝大部分都是在第一次部署以后才产生的.从我自己修改代码的经验出发,我花在阅读既有代码的时间要比编写全新的代码长得多.如果我想减少代码所带来的开销,就应该让它容易读懂.

    注重沟通还可以帮助我们改进思想,让它更加现实.一方面由于投入更多的思考,考虑"如果别人看到这段代码会怎么想"所需要调动的脑细胞,和只关注自己是不一样的.这时我会退后一步,从全新的视角来审视面对的问题和解决方案.另一方面则是由于压力的减轻,因为我知道自己所做的事情是在务正业,我做的是对的.最后,作为社会性的产物,明确地考虑社会因素要比在假设它们不存在的情况下工作更为现实.

    3.1.2 简单

    Edward Tufte做过一个实验,拿过一张图,把上面没有增加任何信息的标记全部擦掉,最终得到了一张很新颖的图,比原先那张更容易理解. ---<Visual Display of Quantitative Information>

    去掉多余的复杂性可以让那些阅读,使用和修改代码的人更容易理解.
    回顾自己做过的事情,把麦子和糠分开,是编程不可或缺的一部分.

    简单存在于旁观者眼中.一个可以把专业工具使用得得心应手的高级程序员,他所认为的简单事情对一个初学者而言可能比登天还难.只有把读者放在心里,才能写出动人的散文.同样,只有把读者放在心里,才能编写出优美的程序.给阅读者一点挑战没有关系,但过多的复杂性会让你失去他们.

    在各个层次上都应当要求简单.

    1. 对代码进行调整,删除所有不提供信息的代码.
    2. 设计中不出现无关的元素.
    3. 对需求提出质疑,找出最本质的概念.

    去掉代码的复杂性后,就好像有一束光照亮的余下的代码,你就有机会用全新的视角来处理他们.

    沟通和简单通常是不可分割的.
    多余的复杂性越少,系统就越容易理解;在沟通方面投入越多,就越容易发现应该被抛弃的复杂性.
    不过,有时我也会发现某种简化会是程序难以理解,这种情况下我会优先考虑沟通.这样的情形很少,但常常都表示这里应该有一些我尚未察觉的更大规模的简化.

    3.1.3 灵活

    在三种价值观中,灵活是衡量那些低效编码与设计实践的一把标尺.

    以获取一个常量为例,我曾经见到有人会用环境变量保存一个目录名,而那个目录下放着一个文件,文件中写着那个常量的值.为什么弄这么复杂?为了灵活. 程序是应该灵活,但只有在发生变化的时候才需如此.如果常量永远不会变化,那付出的代价就白费了.

    因为程序的绝大部分开销都是在它第一次部署以后才产生,所有程序必须要容易改动. 想象中明天或许用得上的灵活性,可能与真正修改代码时所需要的灵活性不是一回事.

    要选择那些提倡灵活性并能带来及时收益的模式.对于会立刻增加成本但收效却缓慢的模式,最好让自己多一点耐心,先把它们放回口袋里,需要的时候再拿出来.

    灵活性的提高可能以复杂性的提高为代价.
    比如给用户提供一个可自定义配置的选择提高了灵活性,但是因为多了一个配置文件,编程时也需要考虑这一点,所以也就更复杂了.

    增加软件的沟通效果同样会提高灵活性.能够快速阅读,理解,修改你的代码的人越多,它将来发生变化的选择就越多.

    3.2 原则

    原则是另一个层次上的通用思想,比价值观更贴近于编程实际,同时又是模式的基础.
    原则可以解释模式背后的动机,它是有普遍意义的.
    正如元素周期表帮助人们发现了新的元素,清晰的原则也可以引出新的模式.在对立的模式间进行选择时,最好的方式就是使用原则来说话,而不是让模式争来争去.最后,如果碰到从未碰到的情况,对原则的理解可以充当我们的向导.

    3.2.1 局部化影响

    组织代码结构时,要保证变化只会产生局部化影响.
    把影响范围缩到最小,代码就会有极佳的沟通效果.它可以被逐步理解,不必一开始就要鸟瞰全景.
    因为实现模式背后一条最主要的动机就是减少变化所引起的代价,所以局部化影响这条原则也是很多模式的形成缘由之一.

    3.2.2 最小化重复

    最小化重复这条原则有助于保证局部化影响.
    如果相同的代码出现在很多地方,那么改动其中一处副本时,就不得不考虑是否需要修改其他副本,变化不再只发生在局部.代码的复制越多,变化的代价就越大.
    复制代码只是重复的一种形式,并行的类层次结构也是其中之一.如果修改一处概念需要修改两个或更多类层次结构,就表示变化的影响已经扩散.此时应该重新组织代码,让变化只对局部产生影响.这种做法可以有效改进代码质量.

    重复不容易被预见到,有时在出现以后一段时间才会被察觉.重复不是罪过,只是增加了变化的开销.

    3.2.3 将逻辑与数据捆绑

    局部化影响的必然结果就是将逻辑与数据捆绑.
    把逻辑与逻辑所处理的数据放在一起,如果有可能尽量放到一个方法(函数)中,或者退一步,放到一个对象里面.在发生变化时,逻辑和数据很可能会同时被改动.如果它们放在一起,那么修改它们所造成的影响就只会停留在局部.

    在编码开始的那一刻,我们往往不清楚改把逻辑和数据放到哪里.我可能在A中编码时才意识到需要B中的数据.在代码正常工作后,我才意识到它与数据离得太远.这时,我需要作出选择:是该把逻辑放到数据那边去,还是把数据挪到逻辑这边来,或者把数据与逻辑都放到一起辅助对象中?也许还可能意识到,我还没找出组合它们以便增进沟通的最好方式.

    3.2.4 对称性

    程序中处处充满了对称性,对称性也是我随时随地运用的一项原则.
    比如,add()方法总会伴随着remove()方法,一组方法会接受同样的参数,一个对象中的所有字段都具有相同的生命周期.
    识别出对称性,把它清晰地表述出来,代码将更容易阅读.一旦读者理解了对称性所涵盖的某一半,他们就会很快地理解另一半.

    对称性往往使用空间词汇进行表述:左右对称,旋转等等.程序中的对称性指的是概念上的对称,而不是图形学上的对称.
    一个缺少对称性的例子:

           void process()
           {
               input();
               count++;
               output();
           }
    

    第二条语句比其他语句更加具体.我会根据对称性的原则重写它:

            void precess()
            {
                input();
                incrementCount();
                output();
            }
    

    上面这个方法依然违法了对称性.这里的input()output()操作都是通过方法意图来命名的,但是incrementCount()这个方法却以实现方式来命名.在追求对称性时,我会考虑为什么我会增加这个数据,于是有了下面的结果:

            void precess()
            {
                input();
                tally();
                output();
            }
    

    在准备消灭重复之前,常常需要寻找并表示出代码中的对称性.

    3.2.5 声明式表达

    实现模式背后的另一条原则是尽可能声明式地表达出意图.

    3.2.6 变化率

    最后一个原则就是把具有相同变化率的逻辑和数据放在一起,把具有不同变化率的逻辑和数据分离.
    变化率具有时间上的对称性,有时候也可以将变化率原则应用于认为的变化.

    比如,开发一套税务软件,我会把计算通用税金的代码和计算某年特定税金的代码分离开.两类代码的变化率是不同的.在下一年中做调整的时候,我会希望能够确保上一年中的代码依然奏效.分离两类代码可以让我更加确信每年的修改只会产生局部化影响.

    变化率原则也适用于数据,一个对象中的所有成员变量的变化率应该差不懂是相同的.
    变化率原则也是对称性的一个应用,不过是时间上的对称性.

    3.3 小结

    实现模式的理论基础:

    1. 价值观
      • 沟通
      • 简单
      • 灵活
    2. 原则
      • 局部化影响
      • 最小化重复
      • 将逻辑与数据捆绑
      • 对称性
      • 声明式表达式
      • 变化率

    相关文章

      网友评论

          本文标题:<实现模式>阅读笔记 --理论

          本文链接:https://www.haomeiwen.com/subject/xioorqtx.html