永远没必要说这本书看的太晚了,只是能再早一点也许会更好。
这里只是一部分笔记和随笔。并非是划重点。原著才是根本。
起一个好名字,会给接下来的事情带来效率。
单字母和数字常量的问题:难以搜索。
但是,一个很长的常量同样不利于阅读。
书上的例子,MAX_CLASSES_PER_STUDENT,个人来说差不多快到极限了。
成员前缀殊无必要
m_lpszName纯属历史遗留。
之前写C#的时候,有时还喜欢用m_ 或者 g_ ,但并不是标准,也不指的提倡。
现代的IDE已经不需要这些额外信息了
前导字母I也是滥用
方法名应该是动词或动词短语
语境
要有意义,以及,包装为更大的概念更好
例如, addrName, addrZipCode还可以
但其实不如address.name, address.zipCode
不要添加额外的语境,比如给每个变量加上gsd前缀这种。
函数应该做一件事。做好这件事。只做这件事。
应该少用switch函数,应以多态替换之。
函数参数:越少越好
函数应当没有副作用(亦即没有非名称中的作用)
举例而言
public void checkSession(session){
if(session.notValid()){
session.initialize();
}
}
上面的函数含有了失败则初始化,这是名称所没有的副作用。
所有名称看不出的作用,都是有害的,是给将来挖的坑。
输出参数
输出参数是有害的。
尤其是在java里面。
在C#里面还算能容忍,因为有明确的out参数:
public int func(int a, out obj b);
在C++里面属于相当讨厌的东西:
public void func(obj* p);
如果不进入函数内部,不知道是不是会改。而在C++里面传递指针又超级普遍。
再说一遍,java中不应当使用输出参数
也许go那种多返回值才是最终答案。
依赖磁铁
例如一个错误枚举类就是依赖磁铁。其修改会导致大范围重新编译。应当尽量避免。
没人能按照这些规则来写函数
所以,正当的流程是:
1st=>operation: 实现
2nd=>operation: 重构
3rd=>operation: 再重构
1st->2nd->3rd
真实只在代码里存在
用代码来阐述
if (empolyee.isEligibleForFullBenefits())
若你想标记右括号,其实应该做的是缩短函数
}//while
}//for(...)
注释就是注释,不要带有html等格式化内容
垂直距离
关系密切的概念应该互相靠近,也不应分布在不同的文件中。
水平对齐
可以考虑拿掉了。
虽然我自己有些时候还是习惯于这样做,特别是常量定义的时候。
得墨忒定律(The Law of Demeter)
模块不应了解他所操作对象的内部情形
亦即下面的代码:
final String s = ctxt.getOptions().getScratchDir();
调用ctxt的模块没有道理知道getOptions()函数返回的对象有什么操作。
以上两条说起来容易,真正做起来难啊。
测试的FIRST规则
必须要吐槽一下,本章所说的Args适用的语法,居然没有给出。
依据对于代码的推测,我推算语法规则如下:渐进
毁坏程序最好的办法就是以改进之名,大动其结构。有些程序将永远无法从这种所谓的“改进”之中恢复过来。
前后一致
例如,如果某个函数用rsp来命名HttpServletResponse对象,那么其他的函数也应当这么做。
如果用的是response,那么大家也都用
重要的不是用什么而是一致
别用算子参数(selector参数)
例如这种函数:func(true,false,true) 完全是噩梦。
图书推荐:Implementation Patterns(实现模式)
封装条件
如果没有上下文,布尔逻辑就难以理解。
应该把解释了条件意图的函数抽离出来。
例如:
if(shouldBeDelete(timer))
要好于
if(timer.hasExpired() && timer.isRecurrent())
否定式难以理解。尽量用肯定式
亦即尽量少用 if(!xxx()) 这种
原文:https://www.cnblogs.com/banruoake/p/11483940.html