業務代碼中,太多 if else 怎麼辦?

點擊上方“芋道源碼”,選擇“設爲星標

管她前浪,還是後浪?

能浪的浪,纔是好浪!

每天 8:55 更新文章,每天掉億點點頭髮...

源碼精品專欄

 

來源:juejin.im/post/5d12228de51d45775c73dd1b

  • if else模式

  • 策略模式

    • 1、首先抽象業務處理器

    • 2、將業務處理器和其支持處理的類型放到一個容器中,java裏Map就是最常用的容器之一

    • 3、定義不同的處理器

    • 4、測試類


前段時間,我將公司系統中的批量審單的功能進行了重構,用到了java的併發編程進行異步化處理,數據庫的樂觀鎖機制處理多線程併發更新數據。其中批量審單的業務處理涉及到多種任務類型,對應不同的業務方法進行處理,比如轉倉,轉快遞,添加贈品,刪除贈品,拆分訂單,批量駁回,批量作廢等等,其中就用到了策略模式。

if else模式

        if ("BATCH_CHANGE_WAREHOUSE".equals(taskType)) {
            //批量轉倉邏輯
        } else if ("BATCH_CHANGE_SHIPPING".equals(taskType)) {
            //批量轉快遞邏輯
        } else if ("BATCH_REPLACE_ORDER_GOODS".equals(taskType)) {
            //批量替換訂單商品邏輯
        } else if ("BATCH_DELETE_ORDER_GOODS".equals(taskType)) {
            //批量刪除訂單商品邏輯
        } else if ("BATCH_ADD_MEMO".equals(taskType)) {
            //批量添加備註邏輯
        } else {
            //任務類型未知
            System.out.println("任務類型無法處理");
        }

看起來,思路清晰,if,else分支也很清楚,但不覺得代碼很臃腫,維護起來麻煩嗎,尤其是其他人來接鍋的時候,連看下去的慾望都沒有了。這時候你需要用策略模式消除其中的if else,進行一下簡單的重構!

策略模式

1、首先抽象業務處理器

public abstract class InspectionSolver {

    public abstract void solve(Long orderId, Long userId);

    public abstract String[] supports();
}

2、將業務處理器和其支持處理的類型放到一個容器中,java裏Map就是最常用的容器之一

@Component
public class InspectionSolverChooser implements ApplicationContextAware{


    private Map<String, InspectionSolver> chooseMap = new HashMap<>();

    public InspectionSolver choose(String type) {
        return chooseMap.get(type);
    }

    @PostConstruct
    public void register() {
        Map<String, InspectionSolver> solverMap = context.getBeansOfType(InspectionSolver.class);
        for (InspectionSolver solver : solverMap.values()) {
            for (String support : solver.supports()) {
                chooseMap.put(support,solver);
            }
        }
    }

    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context=applicationContext;
    }
}

這裏是在應用啓動的時候,加載spring容器中所有InspectionSolver類型的處理器,放到InspectionSolverChooser的map容器中。注意是InspectionSolver類型,所以定義的處理器都得繼承InspectionSolver,其次是spring容器中的才能加載,所以定義的處理器都得放到spring容器中(@Component註解不能少)

3、定義不同的處理器

@Component
public class ChangeWarehouseSolver extends InspectionSolver {

    @Override
    public void solve(Long orderId, Long userId) {
        System.out.println("訂單"+orderId+"開始進行批量轉倉了。。");
    }

    @Override
    public String[] supports() {
        return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE};
    }
}

@Component
public class ChangeShippingSolver extends InspectionSolver{

    @Override
    public void solve(Long orderId, Long userId) {
        System.out.println("訂單"+orderId+"開始進行轉快遞了。。");
    }

    @Override
    public String[] supports() {
        return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_SHIPPING};
    }
}

@Component
public class ReplaceOrderGoodsSolver extends InspectionSolver{

    @Override
    public void solve(Long orderId, Long userId) {
        System.out.println("訂單"+orderId+"開始進行替換商品了");
    }

    @Override
    public String[] supports() {
        return new String[]{InspectionConstant.INSPECTION_TASK_TYPE_BATCH_REPLACE_ORDER_GOODS};
    }
}

4、測試類

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)// 指定spring-boot的啓動類
public class InspectionTest {

    @Autowired
    private InspectionSolverChooser chooser;

    @Test
    public void test() throws Exception{
        //準備數據
        String taskType = InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE;
        Long orderId = 12345L;
        Long userId = 123L;
        //獲取任務類型對應的solver
        InspectionSolver solver = chooser.choose(taskType);
        if (solver == null) {
            throw new RuntimeException("任務類型暫時無法處理!");
        }
        //調用不同solver的方法進行處理
        solver.solve(orderId,userId);
    }
}

在測試類中我消除了可能一長段的if else,從選擇器InspectionSolverChooser中根據type的不同取出不同的任務處理器InspectionSolver,然後調用其solve()方法進行任務處理,不同處理器調用的當然就是不同的solve()方法了,目的達到。



歡迎加入我的知識星球,一起探討架構,交流源碼。加入方式,長按下方二維碼噢

已在知識星球更新源碼解析如下:

最近更新《芋道 SpringBoot 2.X 入門》系列,已經 20 餘篇,覆蓋了 MyBatis、Redis、MongoDB、ES、分庫分表、讀寫分離、SpringMVC、Webflux、權限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能測試等等內容。

提供近 3W 行代碼的 SpringBoot 示例,以及超 4W 行代碼的電商微服務項目。

獲取方式:點“在看”,關注公衆號並回復 666 領取,更多內容陸續奉上。

兄弟,一口,點個????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章