继续占版面分享少许心得。
在Python中也有类似直接指定参数的写法,如:
book_preservation = BookPreservation(user_name="Jack",...)
如果这些参数只是单纯指定进去当作fields的话,
的确这样的写法就够用了:)
下面分享一下这个重构手法的第3个好处:
3. 容易因此将相关功能移入新造的class中,改善程式码分工
假设在我们的租书店程式中,在caller端有以下程式码:
class PreservationChecker{
void checkPreservation(
String userName, String userId, String startTime, String endTime){
BookPreservation bookPreservation = new BookPreservation(
"Jack", "1433717", "2016/5/8", "2016/8/8");
if(!isInTime(
bookPreservation.getStartTime(),
bookPreservation.getEndTime())){
return;
}
// 其他动作
}
boolean isInTime(String startTime, String endTime){
Calendar calendar = Calendar.getInstance();
// 检查过程
return result;
}
// 其他 methods
}
透过上一篇文章中提到的重构手法,我们可以得到以下程式码:
class PreservationChecker{
void checkPreservation(
String userName, String userId, String startTime, String endTime){
TimePeriod timePeriod = new TimePeriod("2016/5/8", "2016/8/8");
BookPreservation bookPreservation = new BookPreservation(
new User("Jack", "1433717"), timePeriod);
if(!isInTime(
timePeriod.getStartTime(),
timePeriod.getEndTime())){
return;
}
// 其他动作
}
boolean isInTime(String startTime, String endTime){
Calendar calendar = Calendar.getInstance();
// 检查过程
return result;
}
// 其他methods
}
以及2个根据参数关系所分离出来的class: User与TimePeriod。
接下来,因为caller端的程式码可能已经太多了,
或是在其他地方也有使用到TimePeriod的时间检查,
好比说、可能另外有个租书店用来举办活动的程式码,
用来检查今天是不是应该给客人30元优惠:
class FesCoupon{
private String startTime;
private String endTime;
double getCouponAmount(){
if(!isInTime(
this.getStartTime(),
this.getEndTime())){
return 0;
}
return 30;
}
// 以下是重复码
boolean isInTime(String startTime, String endTime){
Calendar calendar = Calendar.getInstance();
// 检查过程
return result;
}
}
因为我们先前把BookPreservation的2个时间相关参数,
透过Extract Class,得到了TimePeriod这个class,
我们现在就可以把重复码isInTime()放进去,得到:
class TimePeriod{
private String startTime;
private String endTIme;
boolean isInTime(){
Calendar calendar = Calendar.getInstance();
// 检查过程
return result;
}
}
然后、上述两个引用点就可以精简为:
class PreservationChecker{
void checkPreservation(
String userName, String userId, String startTime, String endTime){
TimePeriod timePeriod = new TimePeriod("2016/5/8", "2016/8/8");
BookPreservation bookPreservation = new BookPreservation(
new User("Jack", "1433717"), timePeriod);
if(!timePeriod.isInTime()){
return;
}
// 其他动作
}
// 其他methods
}
class FesCoupon{
private TimePeriod timePeriod;
double getCouponAmount(){
if(!timePeriod.isInTime()){
return 0;
}
return 30;
}
}
如此,
① 不仅消除了2个caller class当中的重复码,
② 也将isInTime()这个methods放到了与最相关的class当中(也就是TimePeriod)。
即使在支援直接指定参数写法的语言,如Python中,
也能因为这个重构手法,而获得以上2个改善的好处。
※ 引述《leicheong (睡魔)》之铭言:
: ※ 引述《ADYex (宠物狼音树)》之铭言:
: : 例如,假设在一个租书店的程式中有以下程式码:
: : BookPreservation bookPreservation = new BookPreservation(
: : "Jack", "1433717", "2016/5/8", "2016/8/8");
: : 其中4个参数分别为 userName, userId, startTime, endTime,
: : 比较好的作法是将各自相关联的参数各自包装,变成:
: : BookPreservation bookPreservation = new BookPreservation(
: : new User("Jack", "1433717"), new TimePeriod("2016/5/8", "2016/8/8"));
: : 这个重构手法能带来的好处如下:
: : 1. 提升可读性
: : 2. 未来维护简单
: : 3. 容易因此将相关功能移入新造的class中,改善程式码分工
: : 试着像这样将原作法的坏处与新作法的好处跟主管说看看吧。或是块陶。
: 这个的话还需要看在用什么程式语言吧.
: 像在VB和C# v4+上也可以这样写:
: BookPreservation bookPreservation = new BookPreservation(
: userName: "Jack",
: userId: "1433717",
: startTime: "2016/05/08",
: endTime: "2016/08/08");
: 这样写比分拆成用property设定更好. 也是你之前说的“在初始化时设定”
: 和“先全部初始化成null, 在建构完成后再设定”的差别.