命名,对象,数据结构
- 避免误导
accounts 和 accountList,除非 accountList 真的是一个 List 类型,
否则 accounts 会比 accountList 更好。因此像 List,Map这样的后缀,不要随意使用。
- 用明确的意义去表述变量直接的区别。
很多情况下,会有存在 product,productData,productInfo 之类的命名,
Data 和 Info 很多情况下并没有明显的区别,不如直接就使用 product。
- 使用读得出来的名称
- 函数只做一件事,控制参数个数
注释 (注释要精简准确,能不写就不要写;)
- 不易理解的代码添加注释
// kk::mm::ss, MM dd, yyyy
std::string timePattern = "\\d{2}:\\d{2}:\\d{2}, \\d{2} \\d{2}, \\d{4}";
文件(物理)设计
- 一个文件尽量职责单一,功能只处理一件事
- 文件依赖最小
- 仅公开public接口
面向对象设计技巧
Java服务端开发中,三层/四层模型已经成为我们的编码习惯,变成了面向DAO而不是面向对象编程。
缺少模型抽象和设计环节,使得代码冗余,复用程度差。每次都是从DAO的mapper写起。
因此一个好的系统要定义一套好的模型,清楚每个方法的类归属。
- 为每个方法找到合适的类归属,数据和行为放一起
比如定义一个Person类。这个类可以吃饭,睡觉,上厕所,带孩子; 也有很多属性:姓名,年龄,性格... 和明显字段很大程度是定义和描述Person的,但很多行为和我的字段并不相关。 带孩子并不关心你是几岁。如果所有的行为全放在person里,这个类代码就很多。
所以service这时就比较有价值。如果一个行为无法确定是否属于某个领域对象,可以用无状态的service来写。但一定要适度,回归本质,合理划分每个模型的行为。
- 善于使用method object
当一段代码特别复杂时,有各种传参,if/else。我们可以先extract method object. method object 就是一个有数据行为的对象。依赖的数据会成为这个对象的变量,所有的行为会成为这个对象内部的方法。利用成员变量代替 传参,并且把一段过程代码转为对象代码,可以为面向对象编程提供基础(封装,继承,多态)。
class DoMerger{
Map params1; //属性1
Map params2; // 属性2
Do1 do1; //行为1
Do2 do2;
public DoMerger(Map params1,Map params2){
this.params1 = params1;
this.params2 = parmas2;
}
public void invoke(){
do1 = getDo1();
do2 = getDo2();
mergeDO(do1,do2);
}
private Do1 getDo1();
private Do2 getDo2();
private void mergeDo(){
print(do1+do2);
}
}
- 面向接口编程
??怎么做
接口中对外的public接口,一定要有明确的职责。要判断每个public方法是否应该属于同一个interface。 - 正确的使用继承和组合
- 一般情况下组合比继承更加灵活。
- protected abstract 继承,父类保留扩展点,子类扩展。