代码整洁之道的一些准则摘要
好久没有更博了,之前一直在看python的其他库和一些进阶用法。 最近在看《Clean Code》,才疏学浅,整理一下一些常用的写代码应该注意的点吧。
1.命名
- 名副其实;
- 避免误导;
- 做有意义的区分(a1,a2,i,j 这些变量名区分没有任何意义);
- 使用读得出来的名称;
- 使用可搜索的名称(以常量或宏代替魔鬼数字,MAX_CLASSES_PER_STUDENT = 7;)
- 避免使用编码;
- 成员前缀(人们会很快学会无视前缀或后缀,只看到名称中有意义的部分。代码读写得越多,眼中就越没有前缀。最终,前缀变作了不入法眼的废料,变作了旧代码的标志物)(不敢苟同)
- 接口与实现;
- 避免思维映射;
- 类名(类名不应该是动词);
- 方法名(方法名应当是动词或动词短语);
重载构造器时,使用描述了参数的静态工厂方法名。例如:
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
通常好于:
Complex fulcrumPoint = new Complex(23.0)
可以考虑将相应的构造器设置为private,强制使用这种方法。
- 每个概念只对应的一个词(例如controller,driver,manager同义的词不要在一结构体出现多次,容易造成混淆);
- 别用双关语;
- 使用解决方案领域名称;
- 使用源自所涉问题领域的名称;
- 添加有意义的语境;
- 不要添加没用的语境。
2.函数
2.1.函数存在的目的
函数追求的目标是要短小,同时函数的设计的原则: 函数应该做一件事。做好这件事。只做这一件事。 注意函数应该分层,要判断函数是否不止做了一件事,还有一个方法,就是看是否能再拆出一个函数,该函数不仅只是单纯地重新诠释其实现。
2.2.每个函数一个抽象层级
自顶向下读代码:向下规则
按照这个规则分层:
To 做事情1, we should 做事情2 To 做事情2, we should 做事情3 ...
2.3.Switch语句
对待switch语句的正确解决方法是:将switch语句埋到抽象工厂底下,不让任何人看到。该工厂使用switch语句为Employee的派生物创建适当的实体,而不同的函数,如calculatePay,isPayday和deliverPay等,则藉由Employee接口多态地接受派遣。
例如:
public abstract class Employee {
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
---------------------
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
---------------------
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
switch (r.type){
case COMMISSIONED:
return new CommissionedEmployee(r);
case HOURLY:
return new HourlyEmployee(r);
case SALARIED:
return new SalariedEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}
2.4.函数参数
函数最理想的参数数量是零(零参数函数),其次是一(单参数函数),再次是二(双参数函数),应尽量避免三(三参数函数)。
2.5.避免函数产生副作用
副作用是一种谎言。函数承诺只做一件事,但还是会做其他被藏起来的事情。有时,它会对自己类中的变量做出未能预期的改动。有时,它会把变量搞成向函数传递的参数或是系统的全局变量。无论哪种情况,都具有破坏性的,会导致奇怪的时序性耦合及顺序依赖。
2.6.分隔指令与询问
例如在变量的set方法返回类型为void,不应该是bool,不应该包含IsAttrSet,区分好两个方法
- SetAttr
- IsAttrSet
2.7.错误代码抽离
注意两个原则:
- 运用try-catch结构:把错误处理代码从主路径代码中分离出来。
- 最好把try和catch代码块的主体部分抽离出来,另外形成函数。
try {
deletePageAndAllReferences(page);
}
catch (Exception e) {
logError(e);
}
2.8.错误处理就是一件事
处理错误的函数不该做其他事。
未完待续......