代码整洁之道-梳理

目录

 

1.6 童子军军规

第二章:有意义的命名

2.2 名副其实

2.4 做有意义的区分

2.16 添加有意义的语境

第三章:函数

3.2 只做一件事 

3.3 每一个函数一个抽象层

3.4 switch语句

3.7 无副作用

第六章:对象和数据结构

6.1 数据抽象

6.2 数据,对象的反对称性

6.3 得墨忒耳定律

6.4 数据传送对象

第十章:类

10.1 类的组织

10.2 类应该短小

10.2.1 单一职责原则

10.2.2 内聚

10.2.3 保持内聚就会得到许多短小的类

 10.3 为了修改而组织


 

1.6 童子军军规

        光写好代码可不够,必须时刻保持代码整洁,如果每次签入时,代码比签出时干净,那么代码就不会腐坏,清理并不一定会花时间,也许只是改好一个变量名,拆分一个有点过长的函数,消除一点代码重复度,清理一个嵌套的if语句。

第二章:有意义的命名

2.2 名副其实

        我们应该选择指明了计量对象和计量单位的名称:

int elapsedTimeInDays;
int daysSinceCreation;

2.4 做有意义的区分

        废话是另一种没有意义的区分。假设有一个product类,如果还有一个productinfo或productdata类,那么他们的名称虽然不同,意义却无区别,info和data就像a,an,the一样,是意义含混的废话。

        注意,只要体现出有意义的区分,使用a和the这样的前缀就没错。如果缺少明确约定,变量moneyAmout和money没有区别,customerinfo和customer没有区别,accountData和account没区别,theMessage和message没区别。

2.16 添加有意义的语境

        只有一个孤零零的state变量,没人知道这表示什么意思,添加语境-》addrState,这能让读者知道这是某个更大结构的一部分,当然更好的解决方案是创建名为Address的类,这样即使是编译器,也知道这是率属于某个更大的概念了。

        上述图示,可以变量在这边完全不知道是做什么的,但是我们可以给他们封装成一个类,把三个变量做成该类的成员字段

第三章:函数

3.2 只做一件事 

        代码清单3-3中,看上去这个函数是有3件事情,注意,这三件事都是该函数名下同一个抽象层上。如果函数只是做了函数同一抽象层上的步骤,则函数还是只做了一件事情。

        如何判断是否是一个抽象层?  看函数是否能再拆出一个函数。         

3.3 每一个函数一个抽象层

        自顶向下读代码:向下规则

        我们想要让代码拥有自顶向下的阅读顺序,我们想要让每个函数后面都跟着位于下一抽象层级的函数,这样一来,在查看函数列表时,就能循抽象层向下阅读了。

3.4 switch语句

        我们总无法避开switch语句,不过能够确保每个switch都埋在较低抽象层级,而且永远不重复。当然,我们利用多态来实现这一点。

            

        该函数违反了单一职责原则,开闭原则,每当添加新的类型的时候,必须修改它。该问题的解决方案,是将switch埋到抽象工厂下面,不让任何人看到,该工厂使用switch语句问Employee的派生物创建适当的实体,而不同的函数,如calculatePay,isPayday和deliverPay等,则是由Employee接口多态地接受派遣。

3.7 无副作用

        副作用是一种谎言,函数只承诺做一件事情,但还是会做其他被隐藏起来的事情,有时,它会对自己类中的变量做出未能预期的改动。如下图所示,checkPassword中,副作用就是session.initialize(); checkpassword顾名思义是检查密码,该名称并未暗示它会做初始化这次会话的操作。

        输出参数:在面向对象的编程岁月里,有时也需要输出参数,然而,面向对象语言对输出参数额大部分需求已经消失了,因为this也有输出函数的意味在内,换言之,可以使用类似report.appendFooter();普遍而言,应该避免使用输出参数,如果函数必须要修改某种状态,就修改所属对象的状态吧。

第六章:对象和数据结构

6.1 数据抽象

        

         6-2代码漂亮之处在于,你不知道该实现会是在矩形坐标中还是在极坐标中,可能两个都不是,然而,该接口还是明白无误的呈现出了一种数据结构。

        隐藏实现并非只是在变量之间放上一层函数那么简单,隐藏关乎抽象,类并不简单地调用取值器和赋值器将变量推向外间,而是暴露抽象接口,以便用户无需了解数据结构的实现就能操作数据本体。

6.2 数据,对象的反对称性

        下面两个例子说明了对象与数据结构之间的差异,对象把数据结构隐藏于抽象之后,暴露操作数据的函数。数据结构暴露其数据,没有提供有意义的函数。

        代码清单6-5 形状都是简单的数据结构,没有任何行为,所有行为都是在Geometry类中。 

        代码清单6-6,area()方法时多态的,不需要有Geometry类,如果添加一个新的形状,现有的函数都不会受到影响,而添加新函数时,所有类都得修改。

        

        从上面的例子可以看出,对象和数据结构是二分的:过程是代码在于不改动现有数据结构的情况下,添加新函数面向对象代码在于不改动既有函数的前提下添加新类

6.3 得墨忒耳定律

        模块不应该了解它操作对象内部的事情。如上节所述,对象隐藏数据,暴露操作。更准确的说,德墨忒尔定律认为,类C的方法f只应该调用以下对象的方法:

  • 对象C的属性
  • 对象C持有的对象
  • 方法参数传入对象
  • 在方法f中定义的临时对象

6.4 数据传送对象

        Active Record是一种特殊的DTO形式,它们拥有公共变量的数据结构。经常发现开发者往往会将这类数据结构中塞进业务规则方法,把这类数据结构当成对象来用。这将数据结构和对象混为一体了。

        当然了,解决办法就是把Active Record当做数据结构,并创建包含业务规则、隐藏内部数据的独立对象。

第十章:类

10.1 类的组织

        类应该从一组变量开始,如果有公共静态常量,应该先出现,然后是私有静态变量,以及私有实体变量,很少会有公共变量。

        公共函数跟在变量之后,并且应该将公共函数调用的私有函数紧随在该公共函数之后,这符合了自顶向下原则。

10.2 类应该短小

10.2.1 单一职责原则

        类的名字应当描述其权责。实际上,命名正是帮助判断类的长度的一个手段。如果无法为某个类命以精确的名称,这个类大概就太长了。类名越混淆,该类就越有可能拥有过多的权责。

        有大量短小类的系统并不比有少量庞大类的系统拥有更多移动部件,其数量大致相等。问题是:你是想把工具规整到许多抽屉,每个抽屉中装有定义和标记良好的组件箱中呢,还是想要少数几个随便能把所有东西扔进去的抽屉?

        再强调一下:系统应该由许多短小的类而不是少量而巨大的类组成,每个小类封装一个权责,只有一个修改的原因,并与少数其他类一同达成期望的系统行为。

10.2.2 内聚

        类应该只有少量的实体变量。类中的每个方法都应该操作一个或多个这种变量。通常而言,方法操作的变量越多,就越粘聚到类上,如果一个类中的每个变量都被每个方法使用,则该类具有最大的内聚性。

10.2.3 保持内聚就会得到许多短小的类

 10.3 为了修改而组织

        代码清单10-9中,这个类还没有写完,目前还不支持update语句,当需要添加update语句的时候,我们就得“打开”这个类进行修改。

        这样的代码违背了SRP原则,代码清单10-9如何修改呢?sql类中的每个方法都重构到了Sql的派生类中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值