args传入的产品对象应在Main循环创建还是Controller层创建?
架构选择建议
直接选args传入UI层、再转交给Controller,在Controller流程里调用工厂方法创建产品实例的方案,别在Main方法里直接循环调createByName写业务逻辑,核心原因和落地注意点如下:
- 别把Main方法当业务筐。Main的唯一职责是做程序启动的最基础初始化,比如拉起UI、初始化核心依赖,不要往里面塞任何业务逻辑——你现在要做专属优惠,后续大概率要加折扣计算、满减、商品计数这些逻辑,全堆在Main里,后面改优惠规则、加新商品的时候找代码都麻烦。
- 分层要守好职责边界。命令行参数本质是CLI(命令行)这个UI层的输入源,UI层就干两件事:接收原始输入、做最基础的格式校验(比如判断args是不是空、有没有多余的特殊符号),校验完直接把原始参数传给Controller就行,别在UI层做商品对象转换。不然你以后要是想把输入源换成Swing图形界面、HTTP接口,总不能把对象创建的代码复制粘贴三遍吧?
- Controller本来就是干流程协调的活。在这里接收UI传过来的商品名列表,循环调用工厂方法创建Product实例,再把实例丢给购物车Service去做加购、优惠计算、结算,整个链路的逻辑是顺的:
CLI UI:接收args → 基础非空/格式校验 → 传原始参数给Controller
Controller:捕获业务异常(比如你switch里抛的未知商品异常)、协调工厂和Service完成购物车流程
业务Service:纯写购物车逻辑、优惠规则计算,不关心输入是哪来的、商品是怎么创建的
产品工厂:单独存你现在写的createByName逻辑,专职负责根据名称创建商品实例
你现在写的switch创建逻辑本身没毛病,别把它塞在Controller或者Main里就行,单独抽一个ProductFactory类放这段代码,后续加新商品只需要改工厂类,不用动Controller和UI的代码,符合开闭原则,作业交上去结构分会高不少。
给你个最简的分层代码结构参考:
// 程序启动入口 public class Main { public static void main(String[] args) { // 只做初始化,不写业务逻辑 ShopController controller = new ShopController(); new CliUI().run(args, controller); } } // 命令行UI层 public class CliUI { public void run(String[] args, ShopController controller) { // 仅做最基础的输入校验 if (args.length == 0) { System.out.println("请输入要购买的商品名称,多个商品用空格分隔"); return; } try { double totalPrice = controller.checkout(args); System.out.printf("优惠后应付金额:¥%.2f%n", totalPrice); } catch (IllegalArgumentException e) { // 统一处理业务返回的错误,给用户提示 System.out.println("结算失败:" + e.getMessage()); } } } // 控制层,协调业务流程 public class ShopController { private final ProductFactory productFactory = new ProductFactory(); private final CartService cartService = new CartService(); public double checkout(String[] productNames) { Cart cart = new Cart(); for (String name : productNames) { // 在这里调用工厂创建商品实例 Product product = productFactory.createByName(name.trim()); cart.addProduct(product); } // 调用业务层计算优惠和总价 return cartService.calculateFinalPrice(cart); } } // 单独抽的产品工厂类,放你原来的switch逻辑 public class ProductFactory { public Product createByName(String productName) { switch (productName) { case "Soup": return new Soup(); case "Bread": return new Bread(); case "Milk" : return new Milk(); case "Apple" : return new Apple(); default: throw new IllegalArgumentException("不存在的商品:" + productName); } } }
如果你的作业总共就几十行代码,写完就扔不会再改,直接在Main里写也能跑,但既然要求是企业开发级别的优质方案,按上面的分层结构写,职责清晰后续好扩展,比把逻辑全堆在Main里靠谱得多。
内容的提问来源于stack exchange,提问作者Joao Barros
相关产品推荐
相关产品推荐

