代码太长怎么办?试试命令模式

开门见山

某天,我在公园散步打开手机 JD 发现 GTX 3080 TI 显卡上架,正准备付款的时候我看看我的订单详情,就联想到了我以前做的一个订单详情处理的业务。具体的伪代码如下:

public Map<String, List<Object>> doHandler(List<Object> dataList) {
  Map<String, List<Object>> resultMap = new HashMap<>();
  // 实物商品
  if (实物商品) {
    // 数据处理 ...
    resultMap.put("inKindList", mainList);
  }
  
  // 虚拟商品
  if (虚拟商品) {
    // 数据处理 ...
    resultMap.put("virtualList", tradeList);
  }
  
  // 其他商品
  if (其他商品) {
    // 数据处理 ...
    resultMap.put("otherList", otherList);
  }
  return resultMap;
}
复制代码

业务描述

上面我只是简单的对我的数据处理方法做了一个伪代码的表述。对于这种场景就非常类似京东购物下单的情况。

比如:最近618 搞活动我在需要在京东购买一张 GTX 3038 TI 显卡,包含 2 年的质保服务。送一个机械键盘,再加 500 数码品类的优惠券(两张 200 的,一张 100 ),自动关注该店铺送 VIP 不定期推送该店铺活动。我直接购买我的订单假设只有这一个商品。

再把这个场景套回到我的伪代码中。

那么订单详情中主要的信息就可以分为三部分

  1. 商品的主要信息包含: GTX 3038 TI 显卡, 2 年的质保服务
  2. 赠送实物和优惠券:赠送机械键盘,再加 500 数码品类。
  3. 其他辅助信息:比如订单成为某店铺的 VIP , 订阅该店铺活动等。

数据结构

假设我上面提及到的所有订单详情记录都是存储在 order_detail 表中,并且每一订单实物、虚拟商品都存为一条数据。并且我在回显的时候需要做一个分类处理,需要分为三类:商品信息(显卡、质保信息),实物赠送(机械键盘)、优惠券、其他。他们都存在实际价格、优惠价格、原价等。

业务需求

相当于我的需求就是需要将这些商品的价值分别展示在订单详情中,只要是用户在没有支付之前这些这些商品的信息可能都会发生变化,都需要进行实时的计算(个人觉得如果是热点商品肯定这些都是提前预热好的,不能去实时计算的,为了贴合场景咱们假设一下???)。

代码设计

在代码设计之前我们先来看看我的设计, 如下图所示:

通过命令模式批量处理数据.png

为什么是命令模式?

命令模式:它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

适用场景:在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

对于“订单详情” 的这个场景,咱们就可以确定三个分类:主要信息(实物商品)、虚拟商品(优惠券等)、其他商品。这个可以分别对应三个数据处理命令类。

我的代码

我的代码如下,主要是解决订单详情中的信息进行分类显示的问题。

命令接口和参数定义

命令接口如下:

/**
 *  订单详情处理
 */
public interface OrderDetailService {

    Map<String, List<OrderDetailDto>> orderDetailProcess(List<OrderDetailDto> orderDetailList);
}
复制代码

OrderDetailDto 的处理如下:

/**
 *  订单详情
 */
@Data
public class OrderDetailDto {

    private Long id;

    /**
     * 订单编码
     */
    private String orderCode;

    /**
     * 商品编码
     */
    private String commodityCode;

    /**
     * 商品名称
     */
    private Integer commodityType;

    /**
     * 商品名称
     */
    private String commodityName;

    /**
     * 单价
     */
    private BigDecimal commodityUnitPrice;

    /**
     * 商品数量
     */
    private Integer commodityQuantity;

    /**
     * 原价
     */
    private BigDecimal originalPrice;

    /**
     * 折扣价格
     */
    private BigDecimal discountPrice;

    /**
     * 实际价格
     */
    private BigDecimal actualPrice;
}
复制代码

命令实现

实物商品实现类:

/**
 * 实物订单处理
 */
public class InKindOrderDetailCommand implements OrderDetailService {

    @Override
    public Map<String, List<OrderDetailDto>> orderDetailProcess(List<OrderDetailDto> orderDetailList) {
        // 订单中的实物
        List<OrderDetailDto> resultList = orderDetailList.stream()
                // 筛选出实物
                .filter(item -> Objects.equals(1, item.getCommodityType()))
                .peek(item -> {
                    // 计算原价
                    item.setOriginalPrice(item.getCommodityUnitPrice().multiply(new BigDecimal(item.getCommodityQuantity())));
                    // 计算其他数据项目 ....
                }).collect(toList());
        return new HashMap<String, List<OrderDetailDto>>() {
            {
                put("inKind", resultList);
            }
        };
    }
}

复制代码

虚拟商品实现类:

public class VirtualItemOrderDetailCommand implements OrderDetailService {
    @Override
    public Map<String, List<OrderDetailDto>> orderDetailProcess(List<OrderDetailDto> orderDetailList) {
        return null;
    }
}
复制代码

其他商品实现类:

/**
 * 其他物品
 */
public class OtherOrderDetailCommand implements OrderDetailService {

    @Override
    public Map<String, List<OrderDetailDto>> orderDetailProcess(List<OrderDetailDto> orderDetailList) {
        return null;
    }
}
复制代码

命令调用

调用工具类(Terminial 类)

public class OrderDetailServices {

    public List<OrderDetailService> orderDetailServiceList = new ArrayList<>();

    /**
     * 初始化方法
     */
    public static OrderDetailServices create() {
        OrderDetailServices orderDetailServices = new OrderDetailServices();

        // 实物
        OrderDetailService inKindOrderDetail = new InKindOrderDetailCommand();
        // 虚拟物品
        OrderDetailService virtualItemOrderDetail = new VirtualItemOrderDetailCommand();
        // 赠送物品(优惠券、积分)
        OrderDetailService giveAwayOrderDetail = new GiveAwayOrderDetailCommand();
        // 其他
        OrderDetailService otherOrderDetail = new OtherOrderDetailCommand();

        orderDetailServices.orderDetailServiceList =
                Arrays.asList(inKindOrderDetail, virtualItemOrderDetail, giveAwayOrderDetail, otherOrderDetail);
        return orderDetailServices;
    }

    public Map<String, List<OrderDetailDto>> orderDetailProcess(List<OrderDetailDto> orderDetailList) {
        Map<String, List<OrderDetailDto>> resultMap = new HashMap<>();
        for (OrderDetailService item : orderDetailServiceList) {
            Map<String, List<OrderDetailDto>> tmpMap = item.orderDetailProcess(orderDetailList);
            if (tmpMap != null && !tmpMap.isEmpty()) {
                resultMap.putAll(tmpMap);
            }
        }
        return resultMap;
    }
}

复制代码

测试类:

public class OrderDetailServiceTest {

    public static void main(String[] args) {
        OrderDetailServices detailServices = OrderDetailServices.create();
        OrderDetailDto orderDetailDto = new OrderDetailDto();
        orderDetailDto.setOrderCode("CD00001");
        orderDetailDto.setCommodityType(1);
        orderDetailDto.setCommodityName("GTX 3080 TI");
        orderDetailDto.setCommodityUnitPrice(new BigDecimal("8999"));
        orderDetailDto.setCommodityQuantity(2);

        OrderDetailDto orderDetailDto2 = new OrderDetailDto();
        orderDetailDto2.setCommodityType(1);
        orderDetailDto2.setOrderCode("CD00002");
        orderDetailDto2.setCommodityName("LEI SHEN 茶轴 1088");
        orderDetailDto2.setCommodityUnitPrice(new BigDecimal("488"));
        orderDetailDto2.setCommodityQuantity(1);

        OrderDetailDto orderDetailDto3 = new OrderDetailDto();
        orderDetailDto3.setCommodityType(2);
        orderDetailDto3.setOrderCode("CJ00002");
        orderDetailDto3.setCommodityName("满 5000 减 200");
        orderDetailDto3.setCommodityUnitPrice(new BigDecimal("200"));
        orderDetailDto3.setCommodityQuantity(2);

        OrderDetailDto orderDetailDto4 = new OrderDetailDto();
        orderDetailDto4.setCommodityType(2);
        orderDetailDto4.setOrderCode("CJ00002");
        orderDetailDto4.setCommodityName("满 5000 减 100");
        orderDetailDto4.setCommodityUnitPrice(new BigDecimal("100"));
        orderDetailDto4.setCommodityQuantity(1);

        List<OrderDetailDto> detailList = Arrays.asList(
                orderDetailDto,
                orderDetailDto2,
                orderDetailDto3,
                orderDetailDto4);

        Map<String, List<OrderDetailDto>> resultMap = detailServices
                .orderDetailProcess(detailList);
        System.out.println(resultMap);

    }
}
复制代码

总结

命令模式非常适合于数据的处理,支持撤销、重做。将命令处理对象以参数的形式进行传递,最后对数据进行一个统一的处理。它的优缺点如下:

优点:降低耦合度、非常容易拓展、比如上面我在增加一个详情分类非常容易。

缺点:如果当命令非常多的情况下,可能会导致项目的 “类爆炸”。

参考

m.runoob.com/design-patt…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享