在老馬的《重構》第1版中遂赠,將Switch Statement定義成一個代碼壞味道。而且里面提到一句:
大多數(shù)時候晌杰,一看到Switch語句跷睦,你就應該考慮以多態(tài)替換它。
我最初看到這個描述的時候肋演,我持有一點疑慮的抑诸。你仔細想,如果Switch Statement是一個壞味道的話爹殊,那程序中的條件分支(if-else)也是一種壞味道蜕乡,因為if-else和switch從本質(zhì)上都是條件分支。然而梗夸,if-else沒有被公認為一種代碼壞味道层玲,而且在程序中不可避免會用到這個。
在《重構》第2版中反症,老馬直接將這個壞味道改成 Repeated Switches辛块,并做了澄清:
因為在20世紀90年代末,程序員太過于忽視多態(tài)的價值铅碍,我們希望矯枉過正润绵。如今的程序員已經(jīng)更多地使用多態(tài),switch語句也不像15年前那樣有害無益胞谈,很多語言支持更復雜的switch語句尘盼,而不只是根據(jù)基本類型值來做判斷條件憨愉。因此。我們現(xiàn)在更關注重復的Switch
實際上**重復才是罪魁禍首卿捎,重復會讓代碼修改起來更加困難配紫。在第一版中,他其實也提到這點:
從本質(zhì)上講娇澎,switch語句的問題在于重復笨蚁,你會經(jīng)常發(fā)現(xiàn)同樣的switch語句散布在不同的地方。如果為它添加一個新的case字句趟庄,就必須找到所有switch語句并修改它們括细。
作為重構的初學者,當你看到wwitch壞味道的時候戚啥,要抓住重復這個關鍵點奋单,而且重復的switch有可能以if-else體現(xiàn)出來。只要有相同的條件判斷值在多處出現(xiàn)猫十,就散發(fā)出Repeated Switch的味道览濒。沒必要的重復的代碼,是你應該要提高警惕的地方拖云,接下來可能要想點辦法消除它贷笛,比如使用多態(tài)來取代。
這里附上一個重復Switch的案例:
案例一:
public class Item {
private String name;
private int sellIn;
private int quality;
public Item(String name, int sellIn, int quality) {
this.name = name;
this.sellIn = sellIn;
this.quality = quality;
}
@Override
public String toString() {
return this.name + ", " + this.sellIn + ", " + this.quality;
}
void update() {
updateQuality();
updateSellIn();
if (isExpired()) {
updateQualityAfterExpired();
}
}
private boolean isExpired() {
return sellIn < 0;
}
private void updateQuality() {
if (isAgedBrie()) {
if (quality < 50) {
quality = quality + 1;
}
return;
}
if (isBackstagePass()) {
increaseQuality();
if (sellIn < 11) {
increaseQuality();
}
if (sellIn < 6) {
increaseQuality();
}
return;
}
if (isSulfuras()) {
return;
}
if (quality > 0) {
quality = quality - 1;
}
}
private void updateSellIn() {
if (isSulfuras()) {
return;
}
sellIn = sellIn - 1;
}
private void updateQualityAfterExpired() {
if (isAgedBrie()) {
increaseQuality();
return;
}
if (isBackstagePass()) {
quality = 0;
return;
}
if (isSulfuras()) {
return;
}
if (quality > 0) {
quality = quality - 1;
}
}
private void increaseQuality() {
if (quality < 50) {
quality = quality + 1;
}
}
private boolean isSulfuras() {
return name.equals("Sulfuras, Hand of Ragnaros");
}
private boolean isBackstagePass() {
return name.equals("Backstage passes to a TAFKAL80ETC concert");
}
private boolean isAgedBrie() {
return name.equals("Aged Brie");
}
}
案例二:
public class CheckInSystem {
private Map<String, String> checkInRecords = new HashMap<>();
public boolean checkIn(String fingerprint){
Employee employee = EmployeeRepository.query(fingerprint);
int type = employee.getType();
String record;
switch (type) {
case Employee.ENGINEER:
record = "I am an Engineer, My Name is" + employee.getName();
break;
case Employee.SALESMAN:
record = "I am a Salesman, My Name is" + employee.getName();
break;
case Employee.MANAGER:
record = "I am a Manager, My Name is" + employee.getName();
break;
default:
record = "";
}
if (checkInRecords.isEmpty()) {
return false;
}
checkInRecords.put(fingerprint, record);
return true;
}
}
public class Employee {
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
private int type;
private String name;
private int monthlySalary;
private int commission;
private int bonus;
public Employee(int type) {
this.type = type;
}
public int getType() {
return type;
}
public String getName() {
return name;
}
public int payAmount() {
switch (type) {
case ENGINEER:
return monthlySalary;
case SALESMAN:
return monthlySalary + commission;
case MANAGER:
return monthlySalary + bonus;
default:
throw new RuntimeException("Invalid employee");
}
}
}
以上代碼宙项,你找到了重復的Switch了嗎乏苦?