递归和循环的优化

在电子商城项目中,获取目录查询是常见需求。本文从场景描述、数据库表设计(pid表示父目录id,pid=0为顶级目录)到代码实现(递归与循环两种方式),探讨了如何优化这部分功能,强调代码的重构、复用和性能,以提升代码质量。

(一)场景描述

在电子商城项目中,我们会有一个获取目录的查询,目录下面有子目录。在后台的时候,我们怎样获取数据库中已经设计好的目录呢?

首先,面对一个需求,我们想的是,要将这个需求的基本功能进行实现,然后再想优化的事,一般不会立马想到最优方案,当然久经沙场用于丰富的实战经验的将军除外,像我们这些初出茅庐的小兵,只能先填饱肚子,然后再思考怎样优化功能…哈哈,废话,不多说了。

(二)数据库表设计

在这里插入图片描述
pid是父目录的id,当pid为0时,表示为顶级目录。

(三)代码实现

mapper层这些,这里就不再进行赘述了…,这里只展示业务层的代码

  1. 递归实现
    @Override
    public List<ProductType> treeData() {
        return treeDataRecursion(0L);
    }
    
   /**
     * 获取商品的目录结构,
     *      目前实现方式有两种:
     *          其一:使用递归的方式
     *                  通过递归调用,获取所有的子目录,将所有的子目录存入在集合中,
     *                  递归的出口就是当前的子目录集合内为空,及当前目录没有儿子了
     *
     *                  但是递归调用的性能很差,会每递归依次都会发送很多sql,容易给服务器造成很大的压力,用户直观的体验就是系统反应迟缓
     */
    //首先获取所有的儿子
    public List<ProductType> getAllChildren(Long pid){
        Wrapper<ProductType> wrapper = new EntityWrapper<>();
        wrapper.eq("pid",pid);  //此处使用pid,是因为在mapper.xml内,进行另取别名
        return productTypeMapper.selectList(wrapper);
    }

    public List<ProductType> treeDataRecursion(Long pid){
        //首先获取所有的儿子
        List<ProductType> allChildren = getAllChildren(pid);

        //递归的出口,当前集合下面没有儿子
        if(allChildren.size()==0 || allChildren==null){
            return null;
        }
        
        //递归调用,获取当前目录下的子目录
        for (ProductType current : allChildren){
            //获取当前目录的儿子
            List<ProductType> productTypes = treeDataRecursion(current.getId());
            //将儿子设置给当前目录
            current.setChildren(productTypes);
        }

        return allChildren;
    }`
  1. 循环实现
    @Override
    public List<ProductType> treeData() {
        return treeDataLoop();
    }

    /**
     * 获取商品的目录结构,
     *         其二:使用循环的方式
     *                  只发送一条sql,将所有的pid查询到内存,然后再内存中对目录进行组装
     */
    public List<ProductType> treeDataLoop(){

        //1.  只 发送一条sql语句,获取所有的目录 ,此时所有的目录已经存储在内存中
        List<ProductType> allProductType = productTypeMapper.selectList(null);

        //3.  使用集合存放所有的顶级目录
        List<ProductType> first = new ArrayList<>();

        //4.  使用Map,存放所有的对象,包括顶级目录
        Map<Long, ProductType> map = new HashMap<>();
        for (ProductType productType: allProductType) {
            map.put(productType.getId(),productType);
        }

        //2.  对所有的目录进行组装,组装父子关系
        for (ProductType productType: allProductType) {
            //根据数据库中的设计,当目录的pid为0,说明此目录是一个顶级目录,
            if(productType.getPid() == 0){
                //将顶级目录存放到事先准备好的list中
                first.add(productType);
            }else{
                //非顶级目录,需要进行父子关系的组装

                //获取父级目录 ,使用之前的map,避免循环的嵌套使用
                ProductType parentPt = null;
                parentPt = map.get(productType.getPid());

                //将当前的目录添加到父级目录内,作为儿子存在
                parentPt.getChildren().add(productType);
            }
        }

        //5.  最后直接返回顶级目录就可以,因为已经进行了父子的组装,找到父亲,就能找到儿子
        return first;
    }

考虑代码的重构和复用、注重性能的代码才是优质的代码

不断提升吧…共勉

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值