天天看點

JAVA程式設計小技巧--政策模式

作者:極客郭瀚辰

一、定義

政策模式的定義:政策模式就是将一系列算法封裝起來,并使它們之間互相替換。被封裝起來的算法具有獨立性外部不可改變其特性。--《來源于網絡》

二、解決的問題

解決代碼中充斥大量if...else造成高耦合度和複雜度,增加代碼維護成本。

三、UML結構示意圖

JAVA程式設計小技巧--政策模式

四、實際應用

話說小編在入職一家新公司後,接到了一個代碼維護的項目,需要面對一堆的祖傳代碼,其中有一個1000多行的類核心代碼大概像下面這個樣子:

if(condition1){
        
    }else if(condition2){
        
    }else if(condition3){

    }else if(condition4){

    }else{
        
    }           

每個分支中都有數十行甚至數百行代碼,正常情況下小編是不會主動去調整祖傳代碼的,這裡要遵從‘夠用原則’,能跑就行。但是這部分代碼以後需要我來維護,而且就在小編入職不久就修改了兩次,是以,就決定進行優化。

再說一些關于優化代碼的題外話。像小編這種情況各位朋友可能也遇到過,自己編寫代碼的時候也有過類似的情況,項目工期緊、項目初期業務簡單,是以在編碼的合理性上可能會有不妥的地方。首先,我沒有覺得這有什麼不妥,還是夠用原則。但是在業務發生變化的時候,我們就要考慮優化原來編碼中‘不妥’的地方,那麼什麼時候去優化呢?小編給出的建議是,當同一部分代碼改動超過2次以上(再一再二不再三);再者就是,從項目初期就可預見的需要大量的條件判斷,這個時候就不要偷懶了,一定要優化,否則都是給自己挖的坑。

下面開始進行代碼優化,采用政策模式解決上面if...else。為了安全起見,首先将各個判斷語句間的代碼從各個分支中剝離出來,然後進行測試,看看輸出是否有問題,剝離後的代碼如下所示:

if(condition1){
        doSomething1()
    }else if(condition2){
        doSomething2()
    }else if(condition3){
        doSomething3()
    }else if(condition4){
        doSomething4()
    }else{
        doOther()
    }

    doSomething1()
    doSomething2()
    doSomething3()
    doSomething4()
    doOther()           

代碼剝離後,就可以編寫政策代碼,并将各個方法遷移到各自的政策中。

首先,建立HandlerStrategy接口類

interface HandlerStrategy {
    void doSomething();
}           

編寫3個實作類,Handler1、Handler2、Handler3

class Handler1 implements HandlerStrategy{

    @Override
    public void doSomething() {
        System.out.println("Handler1--->doSomething");
    }
}           
class Handler2 implements HandlerStrategy{
    @Override
    public void doSomething() {
        System.out.println("Handler2--->doSomething");
    }
}           
class Handler3 implements HandlerStrategy{
    @Override
    public void doSomething() {
        System.out.println("Handler3--->doSomething");
    }
}           

編寫政策工廠類

final class HandlerProvider {

    private HandlerProvider() {
    }

    static HandlerStrategy getHandler(String type) {
        if (type.equals("Handler1")) {
            return new Handler1();
        } else if (type.equals("Handler2")) {
            return new Handler2();
        } else if (type.equals("Handler3")) {
            return new Handler3();
        } else {
            return null;
        }
    }
}           

上面的代碼完全可以實作功能,但是沒有解決耦合的問題,隻是将耦合點換了個地方,并且每增加一種政策都需要改動工廠類,不符合開閉原則。

繼續優化,增加抽象工廠

public interface HandlerFactory {
    HandlerStrategy createHandler();
}           

分别為不同的handler建立各自的工廠

public class Handler1Factory implements HandlerFactory{
    @Override
    public HandlerStrategy createHandler() {
        return new Handler1();
    }
}           
public class Handler2Factory implements HandlerFactory{
    @Override
    public HandlerStrategy createHandler() {
        return new Handler3();
    }
}           
public class Handler3Factory implements HandlerFactory{
    @Override
    public HandlerStrategy createHandler() {
        return new Handler3();
    }
}           

并将HandlerProvider修改為如下:

final class HandlerProvider {

    private static Map<String,HandlerFactory> handlerFactorys = new HashMap<>(3);

    static {
        handlerFactorys.put("Handler1",new Handler1Factory());
        handlerFactorys.put("Handler2",new Handler2Factory());
        handlerFactorys.put("Handler3",new Handler3Factory());
    }

    private HandlerProvider() {
    }

    static HandlerStrategy getHandler(String type) {
        return handlerFactorys.get(type).createHandler();
    }
}           

此時,我們可以看到已經将if...else優化掉了。但是,新增政策的時候,依然還是要改動

HandlerProvider,并且沒增加一種政策都要對應增加抽象工廠,代碼量相對較大,繼續優化。

将建立handler的抽象工廠類删除,并将建立handler的工廠方法遷移至handler中,代碼如下:

class Handler1 implements HandlerStrategy{

    private Handler1(){}

    static Handler1 getInstance(){
        return new Handler1();
    }
    @Override
    public void doSomething() {
        System.out.println("Handler1--->doSomething");
    }
}           
class Handler2 implements HandlerStrategy{

    private Handler2(){}

    static Handler2 getInstance(){
        return new Handler2();
    }
    @Override
    public void doSomething() {
        System.out.println("Handler2--->doSomething");
    }
}           
class Handler3 implements HandlerStrategy{

    private Handler3(){}

    static Handler3 getInstance(){
        return new Handler3();
    }
    @Override
    public void doSomething() {
        System.out.println("Handler3--->doSomething");
    }
}           

建立枚舉類,EHandler,用于儲存handler類型間的關系,代碼如下:

public enum EHandler {

    Handler1Type(Handler1.getInstance()),
    Handler2Type(Handler2.getInstance()),
    Handler3Type(Handler3.getInstance());

    private HandlerStrategy handlerStrategy;

    public HandlerStrategy getHandlerStrategy(){
        return this.handlerStrategy;
    }
    EHandler(HandlerStrategy handlerStrategy){
        this.handlerStrategy = handlerStrategy;
    }

}           

建立HandlerHelper,用于對外調用使用,整個政策的包,隻對外暴露HandlerHelper,調用者根本不需要知道包内部是如何實作的。

public final class HandlerHelper {

    private HandlerHelper(){}

    public static void doHandler(String type){
        EHandler.valueOf(type).getHandlerStrategy().doSomething();
    }
}           

驗證程式:

public class Main {

    public static void main(String[] args) {
        HandlerHelper.doHandler("Handler1Type");
        HandlerHelper.doHandler("Handler2Type");
        HandlerHelper.doHandler("Handler3Type");
    }

}           

運作結果:

Handler1--->doSomething
Handler2--->doSomething
Handler3--->doSomething           

至此,完成了if...else的優化,不足的地方是新增handler的時候,還是需要維護枚舉類。這個就要看具體的需求了,如果政策數量不是很多可以考慮采用這種方式;如果政策數量多,可以考慮采用反射。

五、複盤

今天主要和大家分享政策模式,順便分享了一下優化代碼的一些心得,并且演練了一下優化if...else的過程。今天的分享就到這裡,歡迎各位小夥伴留言,共同進步。

繼續閱讀