编写可读代码的艺术 - 一次只做一件事

2022-03-28  本文已影响0人  DZQANN

将任务分解,一次只做一件事是单一职责的基础,对于代码的服用也会非常有利

首先书里面举了一个例子,很简单,但是在我们的开发过程中经常会出现

需求比较简单,给一个"location_info"对象,里面有4个字段,LocalityName、SubAdministrativeAreaName、AdministrativeAreaName、CountryName分别对应城市、大城市、州和国家名。给4个字段的值,生成一个Geo的Display。取值逻辑分两部分,第一部分从前面3个字段里取值,优先取靠前的,比如LocalityName有值就不取SubAdministrativeAreaName。如果3个都没有值就用默认的"Middle-ofNowhere"。第二部分取CountryName,如果为空则取"Planet Earth"

public String getDisplay(LocationInfo locationInfo) {
  String place = locationInfo.getLocalityName();
  if (!StringUtils.hasLength(place)) {
    place = locationInfo.getSubAdministrativeAreaName();
  }
  if (!StringUtils.hasLength(place)) {
    place = locationInfo.getAdministrativeAreaName();
  }
  if (!StringUtils.hasLength(place)) {
    place = "Middle-of-Nowhere";
  }
  if (StringUtils.hasLength(locationInfo.getCountryName())) {
    place += ", " + locationInfo.getCountryName();
  } else {
    place += ", Plane Earth";
  }
  return place;
}

对于这段代码,抛开本身说的没有分割任务,我不是很喜欢给一个变量设默认值,然后后面判断不断变化的做法。我更喜欢变量只是短暂的存储一各值,尽量减少变化。

代码比较简单

public class Demo {

    private static final List<Function<LocationInfo, String>> FIRST_PART_GETTERS = ImmutableList.of(
            LocationInfo::getLocalityName,
            LocationInfo::getSubAdministrativeAreaName,
            LocationInfo::getAdministrativeAreaName
    );
    private static final String DEFAULT_FIRST_PART = "Middle-of-Nowhere";
    private static final String DEFAULT_SECOND_PART = "Plane Earth";

    public String getDisplay(LocationInfo locationInfo) {
        return this.getFirstPart(locationInfo) + ", " + this.getSecondPart(locationInfo);
    }

    private String getSecondPart(LocationInfo locationInfo) {
        return StringUtils.hasLength(locationInfo.getCountryName()) ?
                locationInfo.getCountryName() :
                DEFAULT_SECOND_PART;
    }

    private String getFirstPart(LocationInfo locationInfo) {
        return FIRST_PART_GETTERS.stream()
                .map(e->e.apply(locationInfo))
                .filter(StringUtils::hasLength)
                .findFirst()
                .orElse(DEFAULT_FIRST_PART);
    }
}

这样做的好处就是把每一个字段的取值都独立开了,方便增加新的需求,而且代码层次比较清晰,如果我只看getDisplay的话,直接就能知道前面一部分拼上逗号再拼后面一部分。每一个字段的取值逻辑如果有变化也方便修改。

我们的一些接口的塞值逻辑,就是平铺把所有字段的set判断逻辑都写在一个函数里,这样阅读的时候就总有一种被打断的感觉。

上一篇 下一篇

猜你喜欢

热点阅读