你還在用if-else嗎?

蝸蝸小小牛發表於2019-06-27

使用spring容器幹掉if-else

場景說明

最近新做一個專案,需要對不同店鋪的商品做不同處理。例如storeA需要進行handleA操作,storeB需要進行handleB操作,如此類推

大家很容易會想到下面的實現方法

public void handle(String storeName) {
    //店鋪A做操作handleA處理
    if(storeName.equals("storeA")) {
        handleA();
    } else if (storeName.equals("storeB")) {
        handleB(); //店鋪B做操作handleB處理
    } else {
        //其他處理
    }
}

確實上面的程式碼實現簡單易懂,但是如果店鋪越來越多,操作也越來越多的情況下,每新增一個店鋪都需要在這裡新增一次if else,大大的降低了程式碼的可維護性。

解決辦法

這個時候我們會希望可以各個店鋪的處理邏輯之間沒有關聯,互不影響。

抽象介面

我們所有的店鋪都會進行對應的操作,所以首先我們將方法抽象出來

public interface Store {
    void handle();
}

根據不同店鋪做不同處理

@Service("storeA")
public class StoreA implements Store {
    @Override
    void handle() {
        //handleA操作
    }
}
@Service("storeB")
public class StoreB implements Store {
    @Override
    void handle() {
        //handleB操作
    }
}

新增工廠類

這樣還是有問題,因為還是要在業務程式碼中寫if-else來判斷到底是哪家store來進行操作,這個時候可以寫一個工廠類。


public class StoreFactory {

    @Autowired
    @Qualifier("storeA")
    private StoreA storeAA;

    @Autowired
    @Qualifier("storeB")
    private StoreB storeBB;
    
    //其他實現物件

    public Store getStore(String storeName) {

        if (storeName.equals("storeA")) {
            return storeAA;
        } else if (storeName.equals("storeB")) {
           return storeBB;
        }//其他的條件下,返回其他的物件
    }

}

新增工廠類後,我們在要獲取店鋪store時只需要呼叫getStore(String storeName)並傳入店鋪物件名即可,具體返回哪個物件,是storeA還是storeB,就交給工廠類來處理。

還是免不了寫if else,改造StoreFactory

在提供了工廠類之後,還是免不了寫很多的條件判斷,只不過是把所有的條件判斷寫在了一起。這時隨著產品數量的增多,if else 也會不停地增多,維護起來依然費勁。
這裡spring容器就可以派上用場了。spring中有一個BeanFactory物件,也是一個工廠,我們可以用它來改造StoreFactory。

public class StoreFactory {
    @Autowired
    private BeanFactory beanFactory;
    
    public Store getStore(String storeName) {
        Object bean = beanFactory.getBean(storeName);
        if (bean instanceof Store) {
            return (Store) bean;
        }
        throw new UnsupportedOperationException("不支援的店鋪:" + storeName);
    }
}

也可以利用Map自動裝配進行程式碼精簡

@Service
public class StoreFactory {

    @Autowired
    Map<String, Store> stores = new ConcurrentHashMap<>(); //會在初始化的時候將所有的Store自動載入到Map中

    public Store getStore(String store) {
        Store store = stores.get(store);
        if (store == null) {
            throw new RuntimeException("no store defined");
        }
        return store;
    }
}

@Autowired的原始碼中有這樣一段註釋,大意就是@Autowired用於Collection或者Map型別時,容器會自動裝配所有已宣告的value型別的beans。

/* <p>In case of a {@link java.util.Collection} or {@link java.util.Map} dependency type,
 * the container autowires all beans matching the declared value type. For such purposes,
 * the map keys must be declared as type String which will be resolved to the corresponding
 * bean names. Such a container-provided collection will be ordered, taking into account
 * {@link org.springframework.core.Ordered}/{@link org.springframework.core.annotation.Order}
 * values of the target components, otherwise following their registration order in the
 * container. Alternatively, a single matching target bean may also be a generally typed
 * {@code Collection} or {@code Map} itself, getting injected as such.
 */

最後

以上就是全部內容。
歡迎轉載,轉載請說明出處:https://www.cnblogs.com/perryzjl/p/11097106.html

相關文章