实践中的重构31_结果类两种实现的比较

在查询接口结果类设计中,有这么一种思路,即把查询的真实结果和结果码组合起来,形成一个结果类,当调用方使用该接口时,先判断结果是否是成功结果,然后进行相应的处理。
一个示例如下:
/**
* 列表查询结果。
* <p>
* 请在处理成功时[ isSuccess() == true; ]才使用查询结果对象。
* </p>
*
*/
public class QueryListResult {

private List<Book> resultObject;

private ResultCode resultCode;

public QueryListResult() {
}

public QueryListResult(ResultCode resultCode) {
this.resultCode = resultCode;
this.resultObject = null;
}

public QueryListResult(ResultCode resultCode, List<Book> bookList) {
this.resultCode = resultCode;
this.resultObject = bookList;
}

public boolean isSuccess() {
return ResultCode.SUCCESS == resultCode;
}

public List<Book> getResultObject() {
return resultObject;
}

public void setResultObject(List<Book> bookList) {
this.resultObject = bookList;
}

public ResultCode getResultCode() {
return resultCode;
}

public void setResultCode(ResultCode resultCode) {
this.resultCode = resultCode;
}
}

该实现的优点是简单。当需要构建一个失败结果的时候,调用单参数构造方法,当需要构建一个成功结果的时候,调用双参数构造方法。
该实现的缺点如下:
该类没有主动保持自己的不变量,完全依赖调用方对该类不变量的理解。从该类的设计思路,可以很快的推出,该类应该满足以下性质:
任何时刻,该类的结果码不为null。
当结果码为ResultCode.SUCCESS时,该结果为成功结果,调用方可以使用真实的结果对象resultObject。
当结果码不为ResultCode.SUCCESS时,该结果为失败结果,resultCode表明了失败的原因,结果对象resultObject无定义。
默认构造函数导致resultCode为null,单参数构造函数有可能误传null或者成功码,双参数构造函数有可能误传null或者失败码。
总而言之,该对象的不变量的保持,必须依赖调用方的正确使用。
在该类的实际使用中,遵循的标准是失败结果调用单参数构造函数,成功结果调用双参数构造函数,但是由于构造函数和类名同名,该语义没有清晰的表达出来。
因为所有的成功结果都是调用双参数构造函数,因此,在正确使用该类的情况下,传入的resultCode都是ResultCode.SUCCESS,这个实际上是一种重复和冗余的体现。
基于以上的分析,代码重构如下:
/**
* 列表查询结果。
* <p>
* 请在处理成功时[ isSuccess() == true; ]才使用查询结果对象。
* </p>
*
*/
public class QueryListResult {

private List<Book> resultObject;

private ResultCode resultCode = ResultCode.UNKNOWN_EXCEPTION;

public QueryListResult() {
}

public static QueryListResult createFailedResult(ResultCode resultCode) {
QueryListResult failedResult = new QueryListResult();
if (resultCode != ResultCode.SUCCESS && resultCode != null) {
failedResult.resultCode = resultCode;
}
return failedResult;
}

public static QueryListResult createSuccessfulResult(List<Book> bookList) {
QueryListResult successfulResult = new QueryListResult();
successfulResult.resultCode = ResultCode.SUCCESS;
if (bookList == null) {
successfulResult.resultObject = new ArrayList<Book>();
} else {
successfulResult.resultObject = bookList;
}
return successfulResult;
}

public boolean isSuccess() {
return ResultCode.SUCCESS == resultCode;
}

public List<Book> getResultObject() {
return resultObject;
}

public void setResultObject(List<Book> bookList) {
this.resultObject = bookList;
}

public ResultCode getResultCode() {
return resultCode;
}

public void setResultCode(ResultCode resultCode) {
this.resultCode = resultCode;
}
}

resultCode赋予一个默认值ResultCode.UNKNOWN_EXCEPTION,保证了即使使用默认构造函数,创建的对象也是一个合法的对象。
使用静态方法代替构造函数来构建对象,由于静态方法可以自定义方法名,可以明确的指明方法的使用场景。
在静态方法中,使用防御性编程,保持对象的不变量。该处也可以更为强硬的使用异常来指明参数错误。
回收对成功结果结果码的赋值,去除了调用方的对成功结果码的冗余重复使用。
Setter和Getter方法为系统框架使用,为了保持简单,没有加上防御性代码。
代码比重构前稍微复杂一点,但是考虑到该实现可以较好的保持对象的不变量,明确了方法的调用场景,以及去除了冗余代码,个人认为这样的实现优于原有实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值