Re: [討論] 主管不認同書本的知識,說我沒學好程設

作者: ADYex (寵物狼音樹)   2016-05-08 18:32:07
繼續占版面分享少許心得。
在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, 在建構完成後再設定」的差別.
作者: ADYex (寵物狼音樹)   2016-05-08 18:35:00
雖然是用Java舉例,希望這樣看得懂在其他語言中的適用性 :P
作者: ian90911 (xopowo)   2016-05-09 00:49:00

Links booklink

Contact Us: admin [ a t ] ucptt.com