如今假設咱們有兩種類型的訂單,汽車服務訂單和商城配件訂單安全
咱們的抽象訂單接口爲app
public interface Order { public void makeOrder(Order order); }
抽象訂單工廠接口爲dom
public interface OrderFactory { public Order createOrder(); public Order getOrder(); }
現有具體的汽車服務類型訂單ide
@Data @AllArgsConstructor @NoArgsConstructor @ServiceOrderVersion(value = 1) @RequiredArgsConstructor public class ServiceOrder implements Order { private Long id; @NonNull private String code; @NonNull private Store store; @NonNull private ProviderService service; @NonNull private Car car; @NonNull private Date serviceDate; @NonNull private String contact; @NonNull private String contactTel; private AppUser user; @NonNull private String content; private int status; private Date createDate; @Override public void makeOrder(Order order) { ServiceOrderDao serviceOrderDao = SpringBootUtil.getBean(ServiceOrderDao.class); IdService idService = SpringBootUtil.getBean(IdService.class); ((ServiceOrder)order).setId(idService.genId()); AppUser loginAppUser = AppUserUtil.getLoginAppUser(); AppUser user = new AppUser(); user.setId(loginAppUser.getId()); user.setUsername(loginAppUser.getUsername()); ((ServiceOrder)order).setUser(user); ((ServiceOrder)order).setStatus(1); ((ServiceOrder)order).setCreateDate(new Date()); serviceOrderDao.save((ServiceOrder) order); } }
@ServiceOrderVersion版本號以下ui
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ServiceOrderVersion { int value(); }
商城配件訂單略this
具體汽車服務工廠,咱們將其注入Spring容器,不須要每次下單的時候都去掃描包,過濾規則spa
@Component public class ServiceOrderFactory implements OrderFactory { private Set<Class<?>> classes = ClassUtil.getClassSet("com.cloud.ownercar.domain"); private Order createdOrder; @PostConstruct private void initOrder() { this.createdOrder = createOrder(); } @Override public Order createOrder() { Object instance = null; try { //過濾有@OrderVersion標籤的類 instance = classes.stream().filter(clazz -> clazz.isAnnotationPresent(ServiceOrderVersion.class)) //過濾實現了Order接口的類 .filter(clazz -> Order.class.isAssignableFrom(clazz)) //找出版本號大的類,並實例化爲對象 .max(Comparator.comparingInt(clazz -> clazz.getAnnotation(ServiceOrderVersion.class).value())) .get().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return (Order) instance; } @Override public Order getOrder() { return createdOrder; } }
具體配件工廠略線程
另外爲了知足開閉原則,咱們須要加載全部類型的訂單和訂單工廠,之後在新增訂單類型的時候,只須要在指定包下追加新的類型就好。code
@Component public class OrderBean { @Getter private Map<String,Class<?>> orderFactoryMap = new HashMap<>(); @Getter private Map<String,Class<?>> orderMap = new HashMap<>(); @PostConstruct private void init() { Set<Class<?>> classes = ClassUtil.getClassSet("com.cloud.ownercar.domain"); classes.stream().filter(clazz -> OrderFactory.class.isAssignableFrom(clazz)) .forEach(clazz -> orderFactoryMap.put(clazz.getSimpleName(),clazz)); classes.stream().filter(clazz -> Order.class.isAssignableFrom(clazz)) .forEach(clazz -> orderMap.put(clazz.getSimpleName(),clazz)); } }
Controller以下,用傳遞的內容來判斷是哪一種類型的訂單,並給抽象訂單工廠來獲取具體的訂單工廠,經過具體的訂單工廠來生成訂單服務,完成下單功能。考慮到線程安全問題,因此要加ThreadLocal進行保護。這個type是在下單的時候須要提供的訂單類型,好比"ServiceOrder"或者"ProductOrder"或者之後新增的訂單類型。對象
@Slf4j @RestController public class OrderController { private ThreadLocal<OrderFactory> orderFactory = new ThreadLocal<>(); private ThreadLocal<Order> orderService = new ThreadLocal<>(); @Autowired private OrderBean orderBean; @Transactional @SuppressWarnings("unchecked") @PostMapping("/makeeorder") public Result<String> makeOrder(@RequestBody String orderStr, @RequestParam("type") String type) { log.info(orderStr); try { Order order = setOrderFactory(orderStr,type); orderService.get().makeOrder(order); return Result.success("下單成功"); } finally { orderFactory.remove(); orderService.remove(); } } /** * 判斷是哪種類型的訂單來獲取哪種類型的具體訂單工廠 * @param orderStr * @return */ private Order setOrderFactory(String orderStr,String type) { Class<?> classType = orderBean.getOrderMap().get(type); Object order = JSONObject.parseObject(orderStr, classType); // if (orderStr.contains("service")) { // order = JSON.parseObject(orderStr, ServiceOrder.class); // }else if (orderStr.contains("product")) { // order = JSON.parseObject(orderStr, ProductOrder.class); // } Class<?> classFactoryType = orderBean.getOrderFactoryMap().get(type + "Factory"); this.orderFactory.set((OrderFactory) SpringBootUtil.getBean(classFactoryType)); // if (order instanceof ServiceOrder) { // this.orderFactory.set(SpringBootUtil.getBean(ServiceOrderFactory.class)); // }else if (order instanceof ProductOrder) { // this.orderFactory.set(SpringBootUtil.getBean(ProductOrderFactory.class)); // } orderService.set(orderFactory.get().getOrder()); return (Order) order; } }
dao,mapper略