项目背景
在一些商城项目中分类是帮助用户快速定位商品的属性,它可以帮助用户快速定位到他们感兴趣的商品,增加了网站的可用性和效率。那么如何去写好一个分类,从性能去分析考虑,这边博客也许能更好的帮助到你
需求讨论
首先我们还是按照自己项目的分类需求对分类进行划分比如:简单的一级分类(标签、分组),稍微复杂的一些的二三级分类(商品分类,各种大类拆分分类),多级层级分类(IM系统中无法确定的层级关系)
简单分类
- 简单分类 首先最简单的一级分类,这里就不过多赘述了,就是在我们在需要绑定分类的各个对象中新加一个id,然后将来查询的时候关联这个id去查询分类即可。如掘金里面的分类
响应:
java
public class Category {
private String name;
private String description;
// 构造函数、getter和setter略
}
这里的处理时间复杂度一般是O(1)
- 二级分类
到了二级分类,分类的难度就上来了,这个时候我们有两种选择,可以在数据库中去内连接去处理分类,然后我们直接就可以去拿到响应数据,但是在使用数据库服务效率却不是很高,那么我们也可以将类的列表全都取出来然后由服务器代码去处理,这里简单介绍一种思路
第一次遍历的时候,我们将第一层级的数据取出来先添加到我们的响应中,然后使用map由父类的关联id为k,自己本身为v存储到自定义的一个map中。后续在遍历返回的数据,get关联的父级id然后取出list添加到返回中
代码示例:
ini
List<Category> catList = list();
if (CollUtil.isEmpty(catList)) {
return null;
}
// 遍历这些信息,将父级分类和子级分类放到一个map中
List<Map<rCategory, List<rCategory>>> merCategoryVO = Lists.newArrayList();
// 暂存子级分类
Map<Integer, List<rCategory>> childList = new HashMap<>();
for (rCategory category : catList) {
if (ObjUtil.equals(category.getRelevanceId(), 0)) {
//父级分类
Map<rCategory, List<rCategory>> releaseMap = new HashMap<>();
releaseMap.put(category, Lists.newArrayList());
merCategoryVO.add(releaseMap);
} else {
List<rCategory> Categories = Optional.ofNullable(childList.get(category.getRelevanceId()))
.orElse(Lists.newArrayList());
Categories.add(category);
childList.put(category.getRelevanceId(), Categories);
}
}
// 按照父级分类的id,将子级分类放到对应的父级分类中
for (Map<rCategory, List<rCategory>> map : merCategoryVO) {
map.keySet().forEach(key -> {
List<rCategory> list = childList.get(key.getId());
if (CollUtil.isNotEmpty(list)) {
map.put(key, list);
}
});
}
return merCategoryVO;
}
实现效果如下示例: 这样实现的时间复杂度 O(n)
多级分类
那么如果遇到了多级分类,那么也只能采用递归算法了,因为我们无法了解内部分为几层,我们只能采用级别递减的方式去实现分类。话不多说直接提供思路以及dem:
多级分类就需要去考虑递归算法,我们可以简单的将这种方式看为一种树形的结构,里面每一个父类节点都是一个根节点,然后我们遍历根节点的时候就可以传入每个根节点的id以及需要去遍历的数组,在遍历的时候取出这些内容放到这个list中完成递归。
定义返回类型:
java
public class Category {
private int id;
private int pid;
private String name;
private String description;
private List<Category> subcategories;
// 构造函数、getter和setter略
}
实例dem:
创建一个初始化的树形结构
scss
public List<ProCategoryCacheVo> buildTree(){
List<ProCategoryCacheVo> treeCategory = new ArrayList<ProCategoryCacheVo>();
for(ProCategoryCacheVo categoryNode : getRootNode()) {
categoryNode = buildChildTree(categoryNode);
treeCategory.add(categoryNode);
}
return sortList(treeCategory);
}
首先调用的是getRootNode()
方法去获取根节点,道理不变拿的还是我们提前约定好的根节点id
java
private List<ProCategoryCacheVo> getRootNode() {
List<ProCategoryCacheVo> rootMenuLists = new ArrayList<ProCategoryCacheVo>();
for(ProCategoryCacheVo categoryNode : categoryList) {
if(categoryNode.getPid().equals(0)) {
rootMenuLists.add(categoryNode);
}
}
return rootMenuLists;
}
然后我们根据每一个树形结点进入到递归算法中,填充我们获取到的内容
scss
private ProCategoryCacheVo buildChildTree(ProCategoryCacheVo pNode){
List<ProCategoryCacheVo> rootMenuLists = new ArrayList<ProCategoryCacheVo>();
for(ProCategoryCacheVo categoryNode : categoryList) {
if(ObjUtil.equals(categoryNode.getId(),pNode.getId())){
rootMenuLists.add(buildChildTree(categoryNode));
}
}
pNode.setSubcategories(rootMenuLists);
return pNode;
}
那么到这里我们就算获取完成这个树形结构了
下面我们去扩展一下如果要对里面内容安装权重进行排序该如何去处理呢?
同样的还是使用递归算法
java
private List<ProCategoryCacheVo> sortList(List<ProCategoryCacheVo> treeMenus) {
treeMenus = treeMenus.stream().sorted(Comparator.comparing(ProCategoryCacheVo::getSort).reversed()).collect(Collectors.toList());
treeMenus.forEach(e -> {
if (CollUtil.isNotEmpty(e.getChildList())) {
e.setChildList(sortList(e.getChildList()));
}
});
return treeMenus;
}
总结
在Java开发的电商项目中,有效地实现商品分类对于提升用户体验和网站性能至关重要。通过简单分类和多级分类的实现,结合适当的设计模式,我们可以创建一个既灵活又高效的分类系统。记住,代码的可读性和可维护性同样重要,因此应当在实现功能的同时,确保代码的清晰和优雅。