项目需求
商城有很多商品目录,且层级很多。为了对层级目录进行管理,需要满足对层级目录的增删
要求
- 层级目录是保存在DB的,一旦项目进行初始化,需要将层级目录设置为超热点缓存
- 支持在线对层及目录的增删
- 前端获取一次层及目录后,每隔24小时对层级目录进行后台重新获取
- 层及目录更新需要先更新Redis缓存,再更新DB,后台层级目录缓存应该为永不过期缓存
实现方案
1.电商的存储结构
id parentId name
1 0 书籍
2 1 技术书籍
3 1 历史书籍
4 2 并发编程
5 2 设计模式
6 3 二十四史
2.当我们的项目进行初始化的时候,就会将我们的DB里的这些目录进行查询,转化为存储对象
3.将这个对象存储到我们的 Niginx 本地缓存,并设置为永不过期
4.APP、页面进行调用的时候,从Niginx 获取这份儿目录。并且 APP端进行缓存,每隔 24小时进行一次标记位的访问 (如果业务对我们的目录结构有增删,标记位(序号)就会有所变化,前端会再次对数据进行重新的同步)
5.如果有修改,后端是先修改缓存,只针对缓存中需要修改的部分进行修改,然后更新缓存(目录层结构 + 标志位),缓存更新成功后,再更新DB
组合模式组成
- component 抽象构件角色,定义参加组合对象的共有方法和属性
- leaf 叶子构件 叶子对象,其下再也没有其它的分支,也就是遍历的最小单位
- composite 树枝构件,树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构
访问者模式组成
表示一个作用于某对象结构中各个层级元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作
- vistor - 抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的
- concreteVisitor- 具体到访问者他影响访问者访问到一个类之后怎么干,要做什么事情
- element-抽象元素:抽口或者抽象类,声明接收哪一类访问者访问,程序上是通过accpet方法中的参数来定义的
- concreteElement-具体元素:实现accpet方法,通常是vistor.vistor(this),基本上都形成一种模式了
- ObjectStruture-结构对象
代码实现
/**
* @author chongfayi
*/
public abstract class AbstractProductItem {
public abstract void removeChild(AbstractProductItem item);
public abstract void addChild(AbstractProductItem item);
}
/**
* @author chongfayi
*/
@Data
public class ProductItem extends AbstractProductItem {
/**
* id
*/
private int id;
/**
* 父id
*/
private int pid;
/**
* 名称
*/
private String name;
/**
* 叶子节点
*/
private List<ProductItem> child = ListUtil.toList();
@Override
public void removeChild(AbstractProductItem item) {
ProductItem productItem = (ProductItem) item;
this.child = child.stream()
.filter(x -> x.getId() != productItem.getId()).collect(Collectors.toList());
}
@Override
public void addChild(AbstractProductItem item) {
this.child.add((ProductItem) item);
}
}
public interface ItemVisitor<T> {
T visitor(ProductItem productItem);
}
@Component
public class AddItemVisitor implements ItemVisitor<ProductItem>{
@Override
public ProductItem visitor(ProductItem productItem) {
// mock从缓存获取
ProductItem currentItem = MockItem.item;
if (productItem.getId() == currentItem.getId()){
throw new UnsupportedOperationException("根节点不能删除");
}
if (productItem.getPid() == currentItem.getId()){
currentItem.addChild(productItem);
return currentItem;
}
addChild(productItem,currentItem);
return currentItem;
}
private void addChild(ProductItem productItem, ProductItem currentItem) {
for (ProductItem item : currentItem.getChild()) {
if (item.getId() == productItem.getPid()){
item.addChild(productItem);
break;
}else {
addChild(productItem,item);
}
}
}
}
@Component
public class DelItemVisitor implements ItemVisitor<ProductItem>{
@Override
public ProductItem visitor(ProductItem productItem) {
// mock从缓存获取
ProductItem currentItem = MockItem.item;
if (productItem.getId() == currentItem.getId()){
throw new UnsupportedOperationException("根节点不能删除");
}
if (productItem.getPid() == currentItem.getId()){
currentItem.removeChild(productItem);
return currentItem;
}
delChild(productItem,currentItem);
return currentItem;
}
private void delChild(ProductItem productItem, ProductItem currentItem) {
for (ProductItem item : currentItem.getChild()) {
if (item.getId() == productItem.getPid()){
item.removeChild(productItem);
break;
}else {
delChild(productItem,item);
}
}
}
}
public class MockItem {
public static ProductItem item = new ProductItem();
static{
item.setId(1);
item.setPid(0);
item.setName("书籍");
List<ProductItem> productItemList = new ArrayList<>();
item.setChild(productItemList);
ProductItem productItem = new ProductItem();
productItem.setId(2);
productItem.setPid(1);
productItem.setName("技术书籍");
productItemList.add(productItem);
ProductItem productItem1 = new ProductItem();
productItem1.setId(3);
productItem1.setPid(1);
productItem1.setName("历史书籍");
productItemList.add(productItem1);
List<ProductItem> productItemList2 = new ArrayList<>();
ProductItem productItem4 = new ProductItem();
productItem4.setId(6);
productItem4.setPid(3);
productItem4.setName("二十四史");
productItemList2.add(productItem4);
productItem1.setChild(productItemList2);
List<ProductItem> productItemList1 = new ArrayList<>();
ProductItem productItem2 = new ProductItem();
productItem2.setId(4);
productItem2.setPid(2);
productItem2.setName("并发编程");
ProductItem productItem3 = new ProductItem();
productItem3.setId(5);
productItem3.setPid(2);
productItem3.setName("设计模式");
productItemList1.add(productItem2);
productItemList1.add(productItem3);
productItem.setChild(productItemList1);
}
}