如何写出气定神闲的代码——泛型

使用了Mybatis 增强工具包 mybatis-plus: mybatis 增强工具包,简化 CRUD 操作。 文档 http://baomidou.com低代码组件库 http://aizuda.com

java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一-CSDN博客 泛型相关

      本来这里有一大段溢美之词,但是写完感觉也没什么高大上的,但是作为小白下面的代码极其思想是我需要多学习的,之前一直加班,现在有点时间开始欣赏cto的代码;大概介绍一下:简单的三层,采用springboot,redis,baomidou,一切从简原来的mq也去掉了,当然即使mq在,这四个也不是本文的重点;

实体相关:


//这里的id和key是后面的业务需要
public interface ObjectWithId {
    Long getId();
    void setId(Long id);
}
public interface ObjectWithIdAndKey extends ObjectWithId {
    String getKey();
}


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RegionStockBO implements ObjectWithIdAndKey {

    private Long id;
    //……

    @Override
    public String getKey() {
        return "some function to generate key ";
    }
}

//这块我们借助mapstruct进行转换,对于泛型需要了解一下,结合下面RfidBoDoConvertor一起看
public interface BoDoConvertor<BO extends ObjectWithId, DO extends ObjectWithId> extends AllEnumConvertor {

    BO doToBo(DO o);

    List<BO> doListToBoList(List<DO> doList);

    DO boToDo(BO o);

    List<DO> boListToDoList(List<BO> boList);
}

import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface RfidBoDoConvertor extends
        BoDoConvertor<RfidBO, RfidDO>,
        ContainerIdConvertor {
    //ContainerIdConvertor对id为null的处理,省略
}

如果没有BoDoConvertor,我们的转换最简洁的也要类似这样的,而不是只定义接口


@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface BizRuleConverter {

    BizRule toBizRule(BizRuleBO bizRuleBO);

    BizRuleBO toBizRuleBO(BizRuleBO bizRuleBO);

    List<BizRuleBO> toBizRuleBOList(List<BizRule> bizRuleList);
}

当然这样的封装处理的只是针对大部分的情况,如果有其他五花八门需求则需要单写:(当然这是mapstruct的)

@Mapping(target = "salt", ignore = true)
@Mapping(target = "userId", source = "userID")
@Mapping(target = "outboundOrderDO.source", constant = "20")
@Mapping(target = "updateAt", expression = "java(java.time.LocalDateTime.now())")
@Mapping(target = "outboundDetailNum", expression = "java(com.megvii.lbg.fr.wes.utils.IDCreatorUtil.getNextInboundLongId())")
OutboundOrderDetailDO mapOutboundOrderDetailDO(IF009ReceiveInfo if009ReceiveInfo);

@Mapping(target = "outboundOrderDO.orderCreateAt", expression = "java(java.time.LocalDateTime.ofEpochSecond(entry.getValue().get(0).getCreateDt(), 0, java.time.ZoneOffset.ofHours(8)))")
@Mapping(target = "outboundOrderDetailDOList", source = "entry.value")
    OutboundOrderBo mapOutboundOrderByMapEntry(Map.Entry<String, List<IF009ReceiveInfo>> entry);

service例子:先写增删改查的逻辑吧

//二八定律,八成多的代码是简单的,另外的二成可以使其不那么复杂
public interface ContainerService extends ObjectsWithCacheService<ContainerBO, ContainerDO> {

    ContainerBO getVirtualContainerBO();
}

//ObjectWithIdAndKey与ObjectWithId见后面
public interface ObjectsWithCacheService<BO extends ObjectWithIdAndKey, DO extends ObjectWithId> 
  extends IService<DO> {

    BO getObjectById(Long id);

    BO getObjectByKey(String key);

    List<BO> getAllObjects();

    void updateCache(BO value);

    void removeFromCache(Long id);

    void init();

    DO boToDo(BO bo);

    List<DO> boListToDoList(List<BO> boList);

    BO doToBo(DO o);
}

//这块真的省了很多代码,当然也有缺点,先看思想:其实也没啥,武林秘籍就两字:泛型!
/**
 * ObjectsWithCacheServiceImpl
 * ServiceImpl是baomidou的
 * @param <Mapper> baomidou的,继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * @param <DO> 自己的
 * @param <Convertor> 自己的
 * @param <BO> 自己
 */
@Slf4j
@Transactional
public abstract class ObjectsWithCacheServiceImpl<
        Mapper extends BaseMapper<DO>,
        DO extends ObjectWithId,
        Convertor extends BoDoConvertor<BO, DO>,
        BO extends ObjectWithIdAndKey>
        extends ServiceImpl<Mapper, DO>
        implements ObjectsWithCacheService<BO, DO> {

    @Autowired
    protected Convertor convertor;

    protected Map<Long, BO> idMap = new HashMap<>();
    protected Map<Object, BO> valueMap = new HashMap<>();

    @Override
    public BO getObjectById(Long id) {
        return this.idMap.get(id);//id是ObjectWithId
    }

    @Override
    public BO getObjectByKey(String key) {
        return this.valueMap.get(key);//这个key是ObjectWithIdAndKey里面的
    }

    @Override
    public List<BO> getAllObjects() {
        return List.copyOf(this.idMap.values());
    }

    @Override
    public void updateCache(BO bo) {
        this.idMap.put(bo.getId(), bo);
        this.valueMap.put(bo.getKey(), bo);
    }

    @Override
    public void removeFromCache(Long id) {
        this.valueMap.remove(this.idMap.remove(id).getKey());
    }

    @Override
    public void init() {
        var doList = this.getBaseMapper().selectList(new QueryWrapper<>());
        this.idMap.clear();
        this.valueMap.clear();
        doList.forEach(o -> {
            var bo = this.convertor.doToBo(o);
            this.idMap.put(bo.getId(), bo);
            this.valueMap.put(bo.getKey(), bo);
        });
    }

    @Override
    public DO boToDo(BO bo) {
        return this.convertor.boToDo(bo);
    }

    @Override
    public List<DO> boListToDoList(List<BO> boList) {
        return this.convertor.boListToDoList(boList);
    }

    @Override
    public BO doToBo(DO o) {
        return this.convertor.doToBo(o);
    }
}

这样主体代码就写差不多了,但是怎么用哪?给点提示性的提问:idMap,valueMap的数据怎么put又如何get?这时候抬头望望天是想不出来的,上面的代码会给你第二条思路,你看init方法,当然还可以加工这个抽象类让它更巴适:


public interface InventoryLockService extends ObjectsWithCacheService<InventoryLockBO, InventoryLockDO> {}


@Slf4j
@Service
public class InventoryLockServiceImpl
        extends ObjectsWithCacheServiceImpl
        <InventoryLockMapper, InventoryLockDO, InventoryLockBoDoConvertor, InventoryLockBO>
        implements InventoryLockService {

    @Autowired
    private RfidService rfidService;

    @Autowired
    private ContainerService containerService;

    @Autowired
    private RegionStockService regionStockService;

    @Override
    public void init() {
        super.init();//父类,组织数据,下面就是自己的业务处理了
        var reservedRfidBOList = new ArrayList<RfidBO>();
        var reservedContainerList = new ArrayList<ContainerBO>();
        this.idMap.values().forEach(inventoryLockBO -> {
            if (inventoryLockBO.getLockType() == LockTypeEnum.RFID) {
                var rfidBO = this.rfidService.getObjectByKey(inventoryLockBO.getTarget());
                rfidBO.lock(inventoryLockBO, false);
                if (inventoryLockBO.isForReserved()) {
                    reservedRfidBOList.add(rfidBO);
                }
            } else if (inventoryLockBO.getLockType() == LockTypeEnum.CONTAINER) {
                var containerBO = this.containerService.getObjectByKey(inventoryLockBO.getTarget());
                containerBO.lock(inventoryLockBO, false);
                if (inventoryLockBO.isForReserved()) {
                    reservedContainerList.add(containerBO);
                }
            } else {
                throw ErrorCodes.SYSTEM_EXCEPTION.exception("invalid lock type {}", inventoryLockBO.getLockType());
            }
        });
        var stock = RfidBO.calculateStock(reservedRfidBOList);
        for (var containerBO : reservedContainerList) {
            stock.increase(containerBO.getStock());
        }
        this.regionStockService.lockReserve(stock);
    }
}

看完很容易,其中思想入驻大脑,还需要努力

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值