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工厂,能够大大优化代码的简洁程度,减少甚至终结掉硬编码,在此基础上还可以做更多的优化,使得该方法更加优美和强大!通过千条哥架构师的设计,我的奶茶店盈利丰厚,从此走上人生的巅峰~

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