组合模式构建商品类目
概述
将对象组合成树形结构以表示"部分-整体"的层次结构。"Composite 使得用户对单个对象和组合对象的使用具有一致性。
定义 Component 组件
声明一个接口用于访问和管理 Component 的子组件
java
@NoArgsConstructor
public class AbstractProductItem {
protected void addProductItem(AbstractProductItem item) {
throw new UnsupportedOperationException("Not Support child add");
}
protected void delProductChild(AbstractProductItem item) {
throw new UnsupportedOperationException("Not Support child del");
}
}
Composite 树枝组件
Composite 定义子部件的行为。 存储子部件。 在 Component 接口中实现与子部件有关的操作。
java
package com.ssn.design.patterns.service.product.compose;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Composite 树枝组件
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductComposite extends AbstractProductItem{
private Integer id;
private String name;
private Integer pid;
private List<AbstractProductItem> child = new ArrayList<>();
/**
* 新增商品类目
* @param item
*/
@Override
public void addProductItem(AbstractProductItem item) {
this.child.add(item);
}
/**
* 移除商品类目
* @param item
*/
@Override
public void delProductChild(AbstractProductItem item) {
ProductComposite removeItem = (ProductComposite)item;
Iterator iterator = child.iterator();
while (iterator.hasNext()) {
ProductComposite composite = (ProductComposite)iterator.next();
if (composite.getId().equals(removeItem.getId())) {
iterator.remove();
break;
}
}
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public List<AbstractProductItem> getChild() {
return child;
}
public void setChild(List<AbstractProductItem> child) {
this.child = child;
}
}
Client 使用
java
package com.ssn.design.patterns.service.product;
import com.ssn.design.patterns.cache.RedisCommonProcessor;
import com.ssn.design.patterns.pojo.ProductItem;
import com.ssn.design.patterns.repo.ProductItemRepository;
import com.ssn.design.patterns.service.product.compose.AbstractProductItem;
import com.ssn.design.patterns.service.product.compose.ProductComposite;
import com.ssn.design.patterns.service.product.vistor.AddItemVisitor;
import com.ssn.design.patterns.service.product.vistor.DelItemVisitor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class ProductItemService {
private final RedisCommonProcessor redisCommonProcessor;
private final ProductItemRepository productItemRepository;
private final AddItemVisitor addItemVisitor;
private final DelItemVisitor delItemVisitor;
public ProductItemService(RedisCommonProcessor redisCommonProcessor, ProductItemRepository productItemRepository, AddItemVisitor addItemVisitor, DelItemVisitor delItemVisitor) {
this.redisCommonProcessor = redisCommonProcessor;
this.productItemRepository = productItemRepository;
this.addItemVisitor = addItemVisitor;
this.delItemVisitor = delItemVisitor;
}
public ProductComposite fetchAllItems() {
Object cacheItems = redisCommonProcessor.get("items");
if (cacheItems != null) {
return (ProductComposite) cacheItems;
}
List<ProductItem> fetchDbItems = productItemRepository.findAll();
ProductComposite items = genegateProductTree(fetchDbItems);
if (items == null) {
throw new UnsupportedOperationException("Product Items should not be in DB");
}
redisCommonProcessor.set("items",items);
return items;
}
private ProductComposite genegateProductTree(List<ProductItem> fetchDbItems) {
List<ProductComposite> composites = new ArrayList<>();
fetchDbItems.forEach(dbItem -> {
composites.add(ProductComposite.builder()
.id(dbItem.getId()).name(dbItem.getName()).pid(dbItem.getPid())
.build()
);
});
Map<Integer, List<ProductComposite>> groupingList = composites.stream().collect(Collectors.groupingBy(ProductComposite::getPid));
composites.stream().forEach(item -> {
List<ProductComposite> list = groupingList.get(item.getId());
item.setChild(list == null ? new ArrayList<>() : list.stream().map(x -> (AbstractProductItem)x).collect(Collectors.toList()));
});
ProductComposite composite = composites.size() == 0 ? null : composites.get(0);
return composite;
}
}