一般來說使用switch通常會產生一些缺點,e.g.
1. 同樣的 switch 散佈在不同的位置時, 當新的需求出現而需要修改 switch 時,必須找出所有的 switch 一併修改。
2. 因為 switch 代表做了複數的工作,導致 switch 很難符合開閉原則 (OCP)。
3. switch 中條件區塊擴大時會讓 switch 越來越難以理解。
以上的因素也可套用到 if-else。
因此可考慮使用 Strategy Pattern 取代 switch 或是 if-else
簡單的switch如下

    private static void useSwitchExample(){
        switch(condition){
            case 0:
                System.out.println("audio error");
                break;
            case 1:
                System.out.println("client error");
                break;
            case 2:
                System.out.println("not match");
                break;
        }
    }

 
根據 condition 執行不同的 case 條件,會印出不同的錯誤訊息,為了取代 switch ,先建立 Strategy 如下

public interface IErrorStrategy
{
    public void showErrorMessage();
   
    class AudioError implements IErrorStrategy{
        @Override
        public void showErrorMessage()
        {
            System.out.println("audio error");
        }
    }
   
    class ClientError implements IErrorStrategy{
        @Override
        public void showErrorMessage()
        {
            System.out.println("client error");
        }
    }
   
    class NoMatchError implements IErrorStrategy{
        @Override
        public void showErrorMessage()
        {
            System.out.println("no match");
        }
    }
}

 
在 showErrorMessage 方法即是印出各個錯誤代碼,接著建立 Manager 來控制 Strategy e.g.,

public class ErrorStrategyManager
{
    public static final int AUDIO_ERROR = 0;
    public static final int CLIENT_ERROR = 1;
    public static final int NOMATCH_ERROR = 2;
    private Map<Integer, IErrorStrategy> mErrors = new HashMap<Integer, IErrorStrategy>();
    public ErrorStrategyManager() {
        initErrors();
    }
    private void initErrors()
    {
        mErrors.put(CLIENT_ERROR, new IErrorStrategy.ClientError());
        mErrors.put(AUDIO_ERROR, new IErrorStrategy.AudioError());
        mErrors.put(NOMATCH_ERROR, new IErrorStrategy.NoMatchError());
    }
    public void showErrorMessage(int errorMessage)
    {
        IErrorStrategy error = mErrors.get(errorMessage);
        error.showErrorMessage();
    }
}

 
其中使用 map 來對應不同的情況對應不同的 Strategy ,便可取代原本的 switch

    private static void useStrategyInsteadSwitchExample(){
        new ErrorStrategyManager().showErrorMessage(condition);
    }

 
以上的處理方式有個缺點,如果傳入的數值沒有在對應的項目之中就會出現 NullPointerException. e.g.,

new ErrorStrategyManager().showErrorMessage(100);

 
因此我們必須考慮 “例外” 的情況發生,另外判斷 null 的狀態, e.g.,

    public void showErrorMessage(int errorMessage) {
        IErrorStrategy error = mErrors.get(errorMessage);
        if (error != null) {
            error.showErrorMessage();
        } else {
            System.out.println("no this error message");
        }
    }

 
或是確實使用 “例外” 來處理,端看是否把該情況視為例外。

    public void showErrorMessage(int errorMessage) {
        try {
            IErrorStrategy error = mErrors.get(errorMessage);
            error.showErrorMessage();
        } catch (NullPointerException e) {
            System.out.println("no this error message");
        }
    }

 
以下是另外一個範例。
對字串做檢查,判斷字串是否符合某些規則。
一般來說最簡單直覺的方式就是以 if-else 來判斷 e.g.,

        public boolean checkData(String data)
        {
            if(data == null){
                return false;
            }else if(data.equals("")){
                return false;
            }
            return true;
        }

 
當然也具有在開頭提到的種種缺點,因此我們一樣使用 Strategy 來取代 if-else

public interface DataFormatChecker
{
    public static final String TAG = DataFormatChecker.class.getSimpleName();
    public boolean checkData(String data);
    class CheckAllRules implements DataFormatChecker
    {
        private Collection<DataFormatChecker> mRules = new ArrayList<DataFormatChecker>();
        public CheckAllRules() {
            mRules.add(new CheckNull());
            mRules.add(new CheckEmpty());
        }
        @Override
        public boolean checkData(String data)
        {
            for (DataFormatChecker checker : mRules) {
                if (checker.checkData(data)) {
                    Log.d(TAG, "which checker:" + checker.getClass().getSimpleName());
                    return false;
                }
            }
            return true;
        }
    }
    class CheckNull implements DataFormatChecker
    {
        @Override
        public boolean checkData(String data)
        {
            return null == data;
        }
    }
    class CheckEmpty implements DataFormatChecker
    {
        @Override
        public boolean checkData(String data)
        {
            return data.equals("");
        }
    }
}

第7行的 CheckAllRules 會將所有的規則物件放到 list 中,在其 checkData 方法(第18行)將這些規則物件取出並比對字串與規則。
之後若有新的規則只要新增 CheckXXX 類別 implements DataFormatChecker,再加入到 CheckAllRules 的 list 中。
外部呼叫 e.g.,

String data = "1234";
new DataFormatChecker.CheckAllRules().checkData(data);

 
另外也可使用 enum 取代 CheckAllRules e.g,

public interface DataFormatChecker
{
    ...
    public enum CheckAllRules {
        CHECK_NULL(new DataFormatChecker.CheckNull()),
        CHECK_EMPTY(new DataFormatChecker.CheckEmpty());
        private DataFormatChecker mChecker;
        private CheckAllRules(DataFormatChecker checker) {
            mChecker = checker;
        }
        public static boolean checkData(String data)
        {
            for (CheckAllRules type : CheckAllRules.values()) {
                if (type.mChecker.checkData(data)) {
                    Log.d(TAG, "check data error:" + type.mChecker.getClass().getSimpleName());
                    return false;
                }
            }
            Log.d(TAG, "check data valid");
            return true;
        }
    }
    ...
}

 
若有新的規則需求只要新增 CHECK_XXX(new DataFormatChecker.CheckXXX()) 在 enum 中,
並實作 DataFormatChecker.CheckXXX 內容 e.g.。

    public enum CheckAllRules {
        CHECK_NULL(new DataFormatChecker.CheckNull()),
        CHECK_EMPTY(new DataFormatChecker.CheckEmpty()),
        CHECK_LENGTH_MAX(new DataFormatChecker.CheckLengthMax());
        ...
    }
    ...
    class CheckLengthMax implements DataFormatChecker
    {
        @Override
        public boolean checkData(String data)
        {
            return data.length() > 100;
        }
    }

 
外部呼叫不需要修改(符合 OCP),但我們已經新增了另一項檢查規則(Check Length Max)了。

String data = "1234";
new DataFormatChecker.CheckAllRules().checkData(data);