利用策略列舉對討厭的Switch Case 語句進行重構
前言:
重構發生的時機應該在什麼時候呢?
正確:一邊寫著程式碼,當完成之後,馬上想著是否能夠進行重構。
錯誤:寫完程式碼之後,等以後有時間去重構。
即重構本來就不是一件應該特別撥出時間做的事情,重構應該隨時隨地進行。
書上有這麼一句話,我非常喜歡:懶惰是程式設計師的一種美德。正如有句話說,不要讓你的“勤奮”毀掉了你,有著異曲同工之妙。《重構改善既有程式碼的設計》的作者說,“我是個很懶惰的程式設計師,我的懶惰表現形式之一就是:我總是記不住自己寫過的程式碼”,“我不是個偉大的程式設計師,我只是有著一些優秀習慣的好程式設計師”。
什麼是重構:
在不改變程式碼外部行為的前提下,對程式碼做出修改,以改程序序的內部結構。本質上說,重構是在程式碼寫好之後改進它的設計(注意:
舉個栗子:(在筆試的時候經常會有類似重構的例子)
場景:一個影片出租店的程式,計算每一位顧客的消費金額並列印詳單。操作者告訴程式:顧客租了哪些影片、租期多長,程式便根據租賃時間和影片單算出費用。影片分為三類:普通片、兒童片和新片。除了計算費用,還要為常客計算積分,積分會根據租片種類是否為新片而有不同。
未重構前的程式碼如下:
public class Customer { //Movie只是一個簡單的純資料類 private static class Movie{ public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private int _priceCode; public Movie(String title, int priceCode){ _title = title; _priceCode = priceCode; } public int getPriceCode(){ return _priceCode; } public void setPriceCode(int arg){ _priceCode = arg; } public String getTitle(){ return _title; } } //Rental表示某個租客租了一部電影 private static class Rental{ private Movie _movie; private int _daysRented; public Rental(Movie movie, int daysRented){ _movie = movie; _daysRented = daysRented; } public int getDaysRented(){ return _daysRented; } public Movie getMovie(){ return _movie; } } private String _name; private Vector _rentals = new Vector(); public Customer(String name){ _name = name; } public void addRental(Rental arg){ _rentals.addElement(arg); } public String getName(){ return _name; } //以下程式碼是需要重構的主題部分 public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = "Rental Record for " + getName() + "\n"; while(rentals.hasMoreElements()){ double thisAmount = 0; Rental each = (Rental) rentals.nextElement(); //determine amounts for each line switch(each.getMovie().getPriceCode()){ case Movie.REGULAR: thisAmount += 2; if(each.getDaysRented() > 2) thisAmount += (each.getDaysRented() - 2) * 1.5; break; case Movie.NEW_RELEASE: thisAmount += each.getDaysRented() * 3; break; case Movie.CHILDRENS: thisAmount += 1.5; if(each.getDaysRented() > 3) thisAmount += (each.getDaysRented() - 3) * 1.5; break; } //add frequent renter points frequentRenterPoints ++; //add bonus for a two day new release rental if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) frequentRenterPoints ++; //show figures for this rental result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n"; totalAmount += thisAmount; } //add footer lines result += "Amount owed is " + String.valueOf(totalAmount) + "\n"; result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points"; return result; } }
分析:
首先,我一看到switch程式碼,就要看到分支的情況,這裡case只有三個分支型別:Movie.REGULAR,Movie.NEW_RELEASE,Movie.CHILDRENS,如果Movie中新增了一種型別此時case就不支援,因此,至少要新增一個default分支,並且throw 自定義找不到該值的異常,這樣程式更嚴謹。對該例重構的原則如下:
(1)對於switch case 這種語句,我習慣用策略列舉進行重構(具體用法參見:Effective Java 中文版 第2版P128-P136),通過列舉中列舉型別來分型別,對於不同型別處理具體策略採用定義一個抽象方法。
(2)根據高內聚、低耦合的原則,如果某個業務只是跟某個類相關,則將這個業務移動到該類中進行處理。
public class CustomerV2 {
private static class RentalV2{
private MovieV2 _movie;
private int _daysRented;
public RentalV2(MovieV2 movie, int daysRented){
_movie = movie;
_daysRented = daysRented;
}
public int getDaysRented(){
return _daysRented;
}
public MovieV2 getMovie(){
return _movie;
}
public int getRenterPointers(){
if(_movie.equals(MovieV2.NEW_RELEASE) && _daysRented > 1)
return 2;
return 1;
}
}
//通過策略列舉
private static enum MovieV2{
CHILDRENS(2) {
@Override
public double getAmount(int daysRented) {
double amount = 0;
amount += 2;
if(daysRented > 2){
amount += (daysRented -2) * 1.5;
}
return amount;
}
},
REGULAR(0) {
@Override
public double getAmount(int daysRented) {
double amount = 0;
amount += daysRented * 3;
return amount;
}
},
NEW_RELEASE(1) {
@Override
public double getAmount(int daysRented) {
double amount = 0;
if(daysRented > 3)
amount += (daysRented -3) * 1.5;
return amount;
}
};
private String _title;
private final int _priceCode;
MovieV2(int priceCode){
this._priceCode = priceCode;
}
public abstract double getAmount(int daysRented);
}
private String _name;
private Vector _rentals = new Vector();
public CustomerV2(String name){
_name = name;
}
public void addRental(RentalV2 arg){
_rentals.addElement(arg);
}
public String getName(){
return _name;
}
//計算amount和fequent分開
public String statement(){
double totalAmount = getTotalAmounts();
int frequentRenterPointers = getFrequentRenterPointers();
return getReturnData(totalAmount, frequentRenterPointers);
}
private double getTotalAmounts(){
Enumeration rentals = _rentals.elements();
double totalAmount = 0;
while(rentals.hasMoreElements()){
RentalV2 rental = (RentalV2) rentals.nextElement();
MovieV2 movie = rental.getMovie();
double amount = movie.getAmount(rental.getDaysRented());
totalAmount += amount;
}
return totalAmount;
}
private int getFrequentRenterPointers(){
Enumeration rentals = _rentals.elements();
int frequentRenterPointers = 0;
while(rentals.hasMoreElements()){
RentalV2 rental = (RentalV2) rentals.nextElement();
frequentRenterPointers += rental.getRenterPointers();
}
return frequentRenterPointers;
}
private String getReturnData(double totalAmount, int frequentRenterPointers){
String result = "Rental Record for " + getName() + "\n";
result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
result += "You earned " + String.valueOf(frequentRenterPointers) +
" frequent renter points";
return result;
}
}
相關推薦
利用策略列舉對討厭的Switch Case 語句進行重構
前言: 重構發生的時機應該在什麼時候呢? 正確:一邊寫著程式碼,當完成之後,馬上想著是否能夠進行重構。 錯誤:寫完程式碼之後,等以後有時間去重構。 即重構本來就不是一件應該特別撥出時間做的事情,重構應該隨時隨地進行。 書上有這麼一句話,我非常喜歡:懶惰是程式設計師的一種美德
java switch case 語句接列舉類 實現判斷
首先定義列舉類,如: public enum DataTypeEnum { /**小時型別值**/ HOUR("hour"), /**小時型別值**/ DAY("day"), /**小時型別值**/ WEEK("week")
C語言中switch...case語句中break的重要性
不能 實現 比例 重要性 case語句 毫無 ... 應該 switch 在C語言中switch...case語句是經常用到的,下面我介紹一下在使用該語句時候需要註意的一個細節問題。話不多說,直接舉例子: 例子1: switch(fruit) { case 1:printf
switch… case 語句的用法
[] other sta rgs bsp str 復制代碼 ring 表達 public class Test7 { public static void main(String[] args) { int i=5; switch
Switch Case語句中多個值匹配同一個代碼塊的寫法
har com arch mssql pre html www ase cas switch ($p) { case ‘home‘: case ‘‘: $current_home = ‘current‘; break
JavaScript基礎知識(if、if else、else if、while、switch...case語句)
case語句 bubuko ... gpo 控制 java 包含 分享 if...else 13、語句 概念:就是分號(;) 代表一條語句的結束 習慣:一行只編寫一條語句;一行編寫多條語句(代碼可讀性較差) 語句塊:可以包含多條語句 "{ }"將多條語句包裹 u 條
Java中的switch-case語句
sub public return ID PE stat class a case cti class ArithmeticFunction { public static int arithmetic(int a, int b, String operator) {
switch case語句中能否作用在String,long上
bsp lips case語句 nbsp string 類型 span 出了 byte 在之前的eclipse中使用switch的case語句時是只能為(byte,short,char)int類型或枚舉類型。但在jdk1.7以後 在case語句中是可以使用String 以
Python 類似switch/case語句實現方法 獲取文件內容匹配函數並執行
lin get err 容易 main ref 設計 case error 這個主要提供了一種思路,這個不太好理解,我徹底敲了一遍,心裏有點低。參考下面的文章標題:Python switch/case語句實現方法來源:https://blog.csdn.net/l46013
ST語言和C語言關於case of 和switch case語句的區別
C語言中,case後不可直接跟多個常量,要如下圖所示使用(不要忘記defalut) switch(int,char){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: //todo break; defalut: br
if語句,if...else if語句和switch...case語句的區別和分析
當我們有一個判斷條件的時候,顯然用if語句比較方便有效。但當判斷條件很多的時候,我們可以使用if語句或者if....eles 語句和switch case 語句。 if...else if語句和多個if語句的區別還是很大的,if...else if在任何一個環節滿足條件的時候就將會終
用 Python 實現簡單的 switch/case 語句
在Python中是沒有Switch / Case語句的,很多人認為這種語句不夠優雅靈活,在Python中用字典來處理多條件匹配問題字典會更簡單高效,對於有一定經驗的Python玩家不得不承認,的確如此。 但今天我們還是來看看如果一定要用Python來Switch /
switch...case語句的理解案例
switch語句 語法:switch(變數) { case 常量值1: &n
java switch..case語句
語法: switch(變數){ case 變數值1: 程式碼塊1; break; case 變數值2: 程式碼塊2; break; ... case default: 程式碼塊d; break; } swit
C++的if/else語句、switch/case語句
有時候,程式碼中需要實現這樣一個功能:當一個條件為真時做一件事,為假時做另一件事。這就引出了if/else語句。 if/else語句規則如下: 1. 標準格式: if(條件){ //條件為真時做 } else{ //條件為假時做 } 2. 如果條件為假時要什麼都不做,
Java: switch......case.....語句
switch(expression){ case value : //語句 break; //可選 case value : //語句 break; //可選 //你可以有任意數量的case語句 default
用陣列代替if-else和switch-case語句
表驅動法(Table-Driven Approach),通過在表中查詢資訊,來代替很多複雜的if-else或者switch-case邏輯判斷。這是一種設計的技巧,可以應用很多的場合,不僅可以提高程式的效能,也能大大減少程式碼量,使得程式碼變得高效和優雅。下面將
簡單的switch case語句
簡單的switch case語句示例 public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); while
switch-case語句裡面有return了 ,break還起作用嗎?該如何解決
switch-case語句裡面有return了 ,break還起作用嗎?switch-case語句裡面有return了 ,break還起作用嗎? 比如: switch(ID)
switch case 語句要注意!!!
c語言中的switch case 語句相比大家也是非常的清楚的。 無論是誰,在編寫程式碼的時候都會用到這個語句的 ``````````````````````````````````````````