发表于: 2021-06-23 21:08:28
0 1708
今天完成的事情: 知识巩固,
明天计划的事情:请两天假处理点事;来后尽快将angular任务完结,然后加深JS基础知识!
遇到的问题:使用angular 的组件库(NG-Zorro)添加组件没有实现,Zorro引入好的,还没找到添加样式失败的原因;
收获:对象程序设计有三个特征:封装、继承、多态,这三个特征即是语法也是手段
主要说一下封装:
封装很容易被忽视,可能是有人觉得这个太简单了,封装不就是组织代码,不就是构造一个个类,一个个方法
1、认清关系
首先来考虑一个问题,FA调用FB,那么他们是什么关系?理解他们之前的关系重要吗?如果你觉得不重要、就是调用者与被调用者关系(等于没说),就大错特错了。如果你的代码一直写的不好,我觉得很有可能就是这一点没认识清楚。想要回答这个问题,只要考虑另外一个问题,FA为什么要调用FB?——因为FA不调用FB就无法完成自己的工作,FB能帮助自己完成一些事情,也就是说FA依赖FB,他们之间的关系是依赖。这个认识会直接影响到你代码的组织。
1、1 向下原则
依赖者之间的位置或者层次是什么样的?答案是上下的,不是平行的。也就是说FB在FA下层,为FA提供服务,可以参考我们的框架,web层->service层->dao层。《代码整洁之道》里称之为向下原则。
这些东西容易理解,自己写代码时候确容易考虑不到。例:假设有个方法有300行代码,里面有些东西可以封装子F来,你会怎么做?有这么个做法,把方法拆成了三个方法,F1,F2,F3,F1调用F2,F2调用F3,每个方法体里面基本上是假设方法的一段代码,比如F1是1~100行代码,F2是101~200行,F3是201到300行,三个方法需要的参数几乎都是一样的,通过形参依次传递下去,而且返回值都是void类型,方法的名字和注释,意思都很接近。
这个做法怎样?每个方法都是原来方法身体的一部分。从逻辑上他们是平行的,可以认为它还是一个方法,他们之间不是依赖关系。这样封装代码仅仅是把代码挪了个地方,还不如不拆分,阅读者得自己脑补,把代码合并起来才能知道到底想干什么。把一个方法比喻成一个人,那么如果这个方法需要重构,抽离出来的方法仍然必须是个人,是个五脏六武俱全的mini小人,而不是这个人的手或者脚。
1、2 封装不是简简单单的挪动代码
上述例子中,F1调用F2,F2调用F3,或者F1调用F2、F3都可能是合理的,关键看几个F封装的符不符合我们常见的原则,一般来说有以下几个原则。
2、单一职责原则
单一职责,强调的是职责的分离,一个方法只干一件事情,只因为一个原因做修改。很多代码之所以需要重构,因为有职责扩散。所谓职责扩散,就是因为某种原因,职责 P 被分化为粒度更细的职责 P1 和P2 。
从微观上讲,单一职责的方法一目了然,职责明确,利于维护。从宏观上讲是设计的要求,单一职责原则可以看作是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,职责过多,可能引起它变化的原因就越多,从而极大的损伤其内聚性和耦合度。最常见的违反这个原则的例子就是写“大而全”的方法,一个方法搞定各种逻辑,各种flag,各种分支判断,到最后代码看不出主逻辑是什么了。
如果单一职责原则做的好,代码都不会太长,随便翻开Apache的开源软件源码,大部分的方法都没超过100行,当然有些核心类、管理类等,长代码还是有的。
除了大而全的方法,想想上面的F1~F3的例子,有没有违反单一原则?与大多数职责过多相反,它是因没有职责而违反。这里有个“诡辩”,只要不是空方法,只要方法里有代码、有逻辑就有职责,这是个职责范围的认定问题,虽然职责的认定是仁者见仁智者见智的,但是有些基本的东西是确切的,比如职责必须很明确、完整。 上述F1~F3,每个方法都没有完整明确的职责,看代码的感受就是不知道这个方法想干什么,感觉每个方法的存在意义都不大,逻辑合并起开才勉强知道想干什么,所以职责模糊的方法是违反单一原则的。还有就是返回值,有返回值并且设置void的,也属于职责不明确。除非真的没有返回值可以用void,否都应该返回值。隐式返回容易让调用者遗忘哪些变量被改变了,进而引起编程bug。
3、最少知道原则
这也是个非常重要的原则。定义:一个对象应该对其他对象保持最少的了解。就是一个类对自己依赖的类知道的越少越好。也就是,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
函数层次上也要遵循次原则,方法的开口尽可能的小,入参之间不要有依赖,一个极端的例子:一个方法有3个入参,但是第1个和第2个能计算出第3个,就是违反最少知道原则,第三个参数应该在方法体里计算出来。
入参过多很可能会违反最少知道原则,上面的F1,F2,F3的例子,形参个数多达10个。有些很复杂的场景,传递的参数如果真的必须很多的话,考虑用有意义的实体封装,这个封装其实是对入参“归类”,虽然需要的参数还是需要一一“拿到”然后放进实体里,但是归成一类逻辑上可以看成“一个”
4、考虑线程安全问题
线程安全问题平时很难测试到,需要特别注意。静态变量、单例的成员变量都是可能被多个线程访问的、资源的非原子操作(例如数据库一个值读取出来后,再update+1)等等,设计类时把考虑线程是否安全当成一个习惯。
5、好的代码是什么样的
好多人常说优雅,优雅是代码的最高境界。一般来说比较优秀的代码是什么样的?根据上面的解释,以函数为单位,好的代码是一颗树,一颗主干分支分明、错落有致的树。入口函数可以看成树的主干,调用的函数是分支,树是逐渐细化的。如果单独看一个分支的话,它还是一颗树。试想一下,没有分支、只有主干的树是否美观?主干和分支一样粗的树是否美观?一个不平衡的树是否美观?
编写代码是需要一定的审美的,
评论