浏览 1190 次
锁定老帖子 主题:实践中的重构31_结果类两种实现的比较
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-09-13
一个示例如下: /** * 列表查询结果。 * <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方法为系统框架使用,为了保持简单,没有加上防御性代码。 代码比重构前稍微复杂一点,但是考虑到该实现可以较好的保持对象的不变量,明确了方法的调用场景,以及去除了冗余代码,个人认为这样的实现优于原有实现。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |