JAVA 工廠模式與泛型之趣味奶茶店

 一、趣味咖啡廳的開張

     作爲拆二代的我,決定不再繼續揮霍,想搞搞投資,準備開一家奶茶店...

     由於SpringBoot非常便捷與火爆,所以奶茶店採用SpringBoot搭建。

     

二、創建訂單對象

    首先,忽略次要因素,與客戶打交道的肯定是店員,店員與客戶交互時,獲取客戶的需求(這裏指從MQ消息隊列獲取消息或者採用其他方式獲取的報文消息),這裏需要一個載體來保存並記錄這個消息,那這個就是訂單了(一個可以集中解析並保存相似結構報文數據的對象)。


import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class OrderForm {
    private String milkTeaName;//奶茶名稱
    private int price;
    private String type;//此處爲了方便,賦值會與奶茶名稱相同
}

    使用lombok插件,創建了一個很簡單的訂單類,裏面還可以包括一些報文中相似結構的成員參數來保存解析到的數據。此處只是模擬了三個奶茶共有的屬性,甚至可以再加入一個private List<Object> list來存放製作某種奶茶的原材料(也就是保存得到的相似結構體中不同種類,需要有各自執行邏輯的不同數據)。

三、創建一個處理訂單的抽象類

    拿到了一個具體訂單後,肯定都是需要一個固定的模式去製作奶茶,那麼此刻我們可以先創建一個抽象類,來規定奶茶的製作標準。

public abstract class MilkTeaProduction {

    public abstract boolean make(OrderForm orderForm);

}

    簡單明瞭的一個抽象方法,就是製作一杯奶茶,返回一個boolean值,代表製作成功與否。

四、實現抽象方法

    下面,我們只做珍珠奶茶與波霸奶茶的業務,其他業務相似,實現這個抽象類...

//珍珠奶茶
public class PearlMilkTea extends MilkTeaProduction {


    @Override
    public boolean make(OrderForm orderForm) {
        System.out.println(orderForm.getMilkTeaName()+"的特殊業務邏輯");
        System.out.println("奶茶製作完成,製作奶茶爲"+orderForm.getMilkTeaName()+"奶茶!價格爲:"+orderForm.getPrice()+"元");
        return true;
    }
}


//波霸奶茶
public class BobaMilkTea extends MilkTeaProduction{
    @Override
    public boolean make(OrderForm orderForm) {
        System.out.println(orderForm.getMilkTeaName()+"的特殊業務邏輯");
        System.out.println("奶茶製作完成,製作奶茶爲"+orderForm.getMilkTeaName()+"奶茶!價格爲:"+orderForm.getPrice()+"元");
        return true;
    }
}

        其實make()方法就是實現各自特殊的業務邏輯。

五、分發給誰做的的困擾

    雖然現在已經有了製作不同奶茶的步驟,但是如何更優美的判斷不同類型奶茶該走哪一個處理邏輯呢?

//僞代碼
if(type == "珍珠奶茶"){
珍珠奶茶.make(orderForm);
}
if(type == "波霸奶茶"){
波霸奶茶.make(orderForm);
}
if(type == "其他類型"){
...
}

    那麼問題來了,如果今後我的奶茶店如果奶茶品種越來越多,而且隨時可能刪去和添加,那維護起來這個if代碼簡直是個地獄!

    所以我決定高薪聘請一個架構師,因爲這位架構師寫了超過一千條代碼,我們就稱他爲千條哥吧!

    千條哥開始了設計工作...

六、開始搭建奶茶工廠

1、配置Bean

    我們先把Bean配置好,交由Spring容器管理,之後會解釋這樣做的好處。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MilkTeaBeanConfiguration {

    @Bean("BobaMilkTea")
    public BobaMilkTea BobaMilkTeaBean() {
        return new BobaMilkTea();
    }

    @Bean("PearlMilkTea")
    public PearlMilkTea PearlMilkTeaBean() {
        return new PearlMilkTea();
    }


}

2、獲取上下文的工具

    Bean工廠實現了ApplicationContextAware接口中的方法,這個方法能讓我們獲取到spinrg容器中我們配置的所有類,之前是spring幫我們管,但是我們也有能力自己來使用,再實現一個憑藉類名獲取類的方法,這就好比我們有很多不同工作邏輯的製作奶茶的機器,現在我們可以根據奶茶名字,挑出某個特定機器進行製作對應奶茶。

@Component
public class BeanFactory implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (BeanFactory.applicationContext == null) {
            BeanFactory.applicationContext = applicationContext;
        }
    }

    public static Object getObject(String id) {
        Object object = applicationContext.getBean(id);
        return object;
    }
}

3、構建一個訂單處理入口

    這裏就用到了Java的泛化,使用父類(抽象類)來指代所有的子類,運行時決定由那個子類的實現方法來處理,簡直不要太優美與方便。在配置Bean中,我們爲每個特定"奶茶機"都賦予了獨特的名字,我們就可以根據訂單中需要製作奶茶的名字,挑選出特定的奶茶製作機進行製作。只需要把取出的Object對象強轉爲父類(抽象類)即可,這裏就免去了大量的硬編碼判斷,一條代碼聚合所有的奶茶類型,只需要在工廠中根據不同名字拿特定"奶茶機"即可!

 public static boolean handTheOrder(OrderForm orderForm){
        boolean result = false;
        MilkTeaProduction milkTeaFactory = (MilkTeaProduction)BeanFactory.getObject(orderForm.getType());
        if(null != milkTeaFactory){
             result = milkTeaFactory.make(orderForm);
        }else {
            System.out.println("bean獲取失敗!");
            return false;
        }
        return result;
    }

七、創建測試類

public class Main {
    public static void test() {
        OrderForm orderForm_First = OrderForm.builder().milkTeaName("BobaMilkTea").price(11).type("BobaMilkTea").build();
        OrderForm orderForm_second = OrderForm.builder().milkTeaName("PearlMilkTea").price(16).type("PearlMilkTea").build();
        handTheOrder(orderForm_First);
        handTheOrder(orderForm_second);
    }
}

分別產生一個珍珠奶茶,波霸奶茶對象,都交由handTheOrder(OrderForm orderForm)方法處理。

注:自己寫的主函數直接跑是會報錯的!因爲配置的Bean必須要放在Spring容器中,直接運行主函數,spring容器是不會啓動的。所以需要運行SpringBoot自己的入口主函數。

創建一個Controller層來調用:


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

   
   @RequestMapping(value = "test",method = RequestMethod.GET)
    public void test(){
        Main.test();
    }

}

八、運行結果

BobaMilkTea的業務邏輯
奶茶製作完成,製作奶茶爲BobaMilkTea奶茶!價格爲:11元
PearlMilkTea的業務邏輯
奶茶製作完成,製作奶茶爲PearlMilkTea奶茶!價格爲:16元

九、總結

    通過以上的代碼與思想,本設計模式或者說思想,可以處理一些相似結構體的報文,結構相同,只是詳細數據與處理邏輯不同罷了,使用泛化和Bean工廠,能夠大大優化代碼的簡潔程度,減少甚至終結掉硬編碼,在此基礎上還可以做更多的優化,使得該方法更加優美和強大!通過千條哥架構師的設計,我的奶茶店盈利豐厚,從此走上人生的巔峯~

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