代码之丑 例子

1,命名例子

这段代码做了什么?

public void processChapter(long chapterId) {
  Chapter chapter = this.repository.findByChapterId(chapterId);
  if (chapter == null) {
    throw new IllegalArgumentException("Unknown chapter [" + chapterId + "]");  
  }
  
  chapter.setTranslationState(TranslationState.TRANSLATING);
  this.repository.save(chapter);
}

 

 

根据章节id从数据库中读取章节,把章节的状态改为翻译中,再把章节写回数据库。

 

 

把一个章节的翻译状态改为翻译中。

问题:需要阅读这段代码的细节,才能知道这段代码是做什么的?

将章节的状态改为翻译中,叫处理章节。

将章节的状态改为翻译完成,是不是也叫处理章节?

修改章节内容也叫处理章节?

命名过于宽泛,没有错,但不精准。

 

命名首先要能够描述这段代码做的事情。changeChapterToTranslating

如果把细节平铺开来,那本质上和直接阅读细节差别不大。

一个好的名字应该描述意图,而非细节。

我们为什么把翻译状态改为翻译中,这一定是有原因的,也就是意图。具体到这里的业务,我们把翻译状态修改为翻译中,是因为我们在这里开启了一个翻译的过程。所以,这段函数应该命名startTranslation。

 2,

if (user.isEditor()) {
  service.editChapter(chapterId, title, content, true);
} else {
  service.editChapter(chapterId, title, content, false);
}

if判断的是参数,而不是动作。

boolean approved = user.isEditor();
service.editChapter(chapterId, title, content, approved);

boolean approved = isApproved(user);
service.editChapter(chapterId, title, content, approved);


private boolean isApproved(final User user) {
  return user.isEditor();
}

 3,代码一次加一点,逐渐变坏

if (code == 400 || code == 401) {
  // 做一些错误处理
}

if (code == 400 || code == 401 || code == 402) {
  // 做一些错误处理
}

if (code == 400 || code == 401 || code == 402 || ...
  || code == 500 || ...
  || ...
  || code == 10000 || ...) {
  // 做一些错误处理
}

 

任何代码都经不起这种无意识的累积,每个人都没做错,但最终的结果很糟糕。

让营地比你来时更干净。

 4, 大类,职责不单一

用户类

public class User {
  private long userId;
  private String name;
  private String nickname;
  private String email;
  private String phoneNumber;
  private AuthorType authorType;
  private ReviewStatus authorReviewStatus;
  private EditorType editorType;
  ...
}

用户Id, 姓名,昵称,邮箱,电话号码

作者类型,表示作者是签约作者还是普通作者。签约作者可以设置作品的付费信息,而普通作者不能。

authorReviewStatus作者审核状态,作者成为签约作者,需要有一个申请审核的过程,这个状态就是审核的的状态。

编辑类型,编辑可以是主编,也可以是小编,他们的权限不一样。

 

对普通用户,普通用户既不是作者,也不是编辑。作者和编辑相关的字段,对普通用户来说没有意义。

对作者,编辑相关的字段也没有意义,作者是不能成为编辑的。

对编辑,作者相关的字段没有意义,编辑也不会成为作者。

问题:只有一个用户类。

public class User {
  private long userId;
  private String name;
  private String nickname;
  private String email;
  private String phoneNumber;
  ...
}

作者类,

public class Author {
  private long userId;
  private AuthorType authorType;
  private ReviewStatus authorReviewStatus;
  ...
}

编辑类,

public class Editor {
  private long userId;
  private EditorType editorType;
  ...
}

拆出Author和Editor两个类,把作者和编辑相关的字段分别移到了这两个类里面。

在这两个类里分别有一个userId字段,用以识别这个角色是和哪个用户相关。

 5,大类,字段分组

有时候,我们会觉得有一些字段确实都属于某个类,结果就是,这个类还是很大。

比如拆完的新的User类。

public class User {
  private long userId;
  private String name;
  private String nickname;
  private String email;
  private String phoneNumber;
  ...
}

 

这些字段应该都算用户信息的一部分。但是,即便是相比于原来的User类小了很多。这个类依然也不算是一个小类。

原因就是,这个类里面的字段并不属于同一种类型的信息。比如,userId,name,nickname 几项,算是用户的基本信息,

而email, phoneNumber这些属于用户的联系方式。

 

从需求上看,基本信息是那种一旦确定就不怎么会改变的内容,而联系方式则会根据实际情况调整。比如,绑定各种社交媒体的账号。

 

如果我们把这些信息都放到一个类里面,这个类的稳定程度就要差一些。

把User类的字段分组,把不同的信息放到不同的类里面。

public class User {
  private long userId;
  private String name;
  private String nickname;
  private Contact contact;
  ...
}

联系方式类

public class Contact {
  private String email;
  private String phoneNumber;
  ...
}

把email和PhoneNumber放进去,后面再有任何关于联系方式的调整就放这个类里。

 6,基本类型偏执

public double getEpubPrice(final boolean highQuality, final int chapterSequence) {
  ...
}

根据章节信息获取EPUB(一种电子书格式)的价格。

问题出在返回值的类型上,也就是价格的类型上。

我们在数据库中存储价格的时候,就是用一个浮点数,这里用double可以保证计算的精度,这样的设计有什么问题?

 

这是很多人使用基本类型(Primitive)作为变量类型思考的角度。

实际上,这种采用基本类型的设计缺少了一个模型。

 

虽然价格本身是用浮点数在存储,但是价格和浮点数本身并不是同一个概念,有着不同的行为需求。

比如,一般情况下,我们要求商品的价格是大于0的,但double类型本身是没有这种限制的。

 

用double类型限制。要在使用的地方都保证价格的正确性,价格效应到处都是。

if (price <= 0) {
  throw new IllegalArgumentException("Price should be positive");
}

补齐这里缺失的模型,我们可以引入Price类型。校验在初始化时进行:

class Price {
  private long price;
  
  public Price(final double price) {
    if (price <= 0) {
      throw new IllegalArgumentException("Price should be positive");
    }
    
    this.price = price;
  }
}

 

以对象取代基本类型

 

posted @ 2021-07-06 07:06  starof  阅读(226)  评论(0编辑  收藏  举报