将任务分解,一次只做一件事是单一职责的基础,对于代码的服用也会非常有利
首先书里面举了一个例子,很简单,但是在我们的开发过程中经常会出现
需求比较简单,给一个"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判断逻辑都写在一个函数里,这样阅读的时候就总有一种被打断的感觉。
网友评论