商品分类以及统计

     在卓越网首页的左边,或者当当网的左边,都有商品分类列表,并会显示旗下的商品有多少种。如何在计算机中描述?那可定是用树来表示。但要高效地完成这个功能会面临哪些问题?

    1、怎么统计某一分类的商品种类

    2、如果更改某一分类商品种类数量,怎么通知其他节点

    3、对于非叶子节,是否要记录商品数,

    4、如果增加新的商品类型,又怎么做

 

    对于这些问题,我认为关键的一点是:一旦有数据变化,就要通知双亲,直到根节点。这样一来,每当获取某一中分类的商品种类数时,它会检测是否收到通知,如果收到,则重新计算;否则直接返回数量。

    2011年9月,引入CommodityVisitor和CommoditySearcher,用来处理遍历和检索两种情况;重写计算商品分类数量的相关函数;删除多余函数。

   废话不多说,直接贴代码,欢迎拍砖。

 

 

/**
 * 商品分类
 */
public class CommodityClassify implements Cloneable {
    private static final int ZERO = 0;
    //*************************  节点属性  ******************************
    /**
     * 该分类名称
     */
    private String name;
    /**
     * 商品分数码
     */
    private String code;
    /**
     * 该分类下的商品种类数
     */
    private int amount = ZERO;
    /**
     * 是否要计算商品种类
     */
    private boolean needRecount = true;

    //*************************** 树形关系  *********************************
    /**
     * 双亲结点
     */
    private CommodityClassify parent;
    /**
     * 孩子结点
     */
    private List<CommodityClassify> children = Collections.synchronizedList(new LinkedList<CommodityClassify>());

    public CommodityClassify(String name, String code) {
        this(name, code, ZERO);
    }

    public CommodityClassify(String name, String code, int amount) {
        this.name = name;
        this.code = code;
        this.amount = amount;
    }

    /**
     * 调整节点的amount
     *
     * @param amount
     */
    public synchronized void adjustAmount(int amount) {
        //1、如果是叶子节点,则传入amount,否则跳过
        if (isLeafy() && this.amount != amount) {
            this.amount = amount;
            onAmountChange();
        }
    }

    /**
     * 判断是否为叶子节点
     */
    public boolean isLeafy() {
        return 0 == children.size();
    }

    /**
     * 计算当前节点的商品种类
     */
    public int calcAmount() {
        if (needRecount && !isLeafy()) {
            amount = ZERO;
            for (CommodityClassify cc : children) {
                amount += cc.calcAmount();
            }
            needRecount = false;
        }
        return amount;
    }

    /**
     * 返回深度
     *
     * @return
     */
    public int getDepth() {
        int depth = 1;
        CommodityClassify root = parent;
        while (root != null) {
            depth += 1;
            root = root.getParent();

        }
        return depth;
    }

    //*************************  getter/setter  ******************************
    protected void setChildren(List<CommodityClassify> children) {
        this.children = children;
    }

    public boolean isNeedRecount() {
        return needRecount;
    }

    private void setNeedRecount(boolean needRecount) {
        this.needRecount = needRecount;
    }

    public CommodityClassify getParent() {
        return parent;
    }

    public void setParent(CommodityClassify parent) {
        this.parent = parent;
    }

    public String getName() {
        return name;
    }

    public String getCode() {
        return code;
    }

    public List<CommodityClassify> getChildren() {
        return children;
    }

    public int getAmount() {
        return amount;
    }
    //*********************  节点操作  **********************

    /**
     * 增加孩子结点
     * 需要同步
     *
     * @param cc
     */
    private void addChild(CommodityClassify cc) {
        //1、设置双亲节点
        cc.setParent(this);
        //2、增加叶子节点
        children.add(cc);
        onAmountChange();
    }
    /**
     * 删除孩子节点
     *
     * @param cc
     */
    private void removeChild(CommodityClassify cc) {
        //1、待删除的节点清空双亲
        cc.setParent(null);
        //2、删除节点
        children.remove(cc);
        //3、通知变化
        onAmountChange();
    }
    /**
     * 返回根节点
     *
     * @return
     */
    private CommodityClassify getRoot() {
        CommodityClassify root = this;
        while (root.parent != null) {
            root = root.parent;
        }
        return root;
    }

    /**
     * 商品分类的数量变化时,重新计算
     */
    private void onAmountChange() {
        notifyParentChange();
        recountTotal();
    }

    /**
     * 通知双亲结点:数据已经改变
     */
    private void notifyParentChange() {
        //通知当前当前结点数据变化
        this.setNeedRecount(true);
        //通知双亲结点数据已经变化
        CommodityClassify parents = this.parent;
        while (parents != null) {
            parents.setNeedRecount(true);
            parents = parents.parent;
        }
    }

    /**
     * 重新计算 商品 总数
     */
    private void recountTotal() {
        this.getRoot().calcAmount();
    }


    //*************************  遍历 **************************

    /**
     * 广度优先遍历
     */
    public void breadthFirstTraversal(CommodityVisitor visitor) {
        Queue<CommodityClassify> queue = new LinkedList<CommodityClassify>();
        queue.add(this);
        while (!queue.isEmpty()) {
            CommodityClassify c = queue.poll();
            visitor.visit(c);
            queue.addAll(c.getChildren());
        }
    }

    /**
     * 返回层次遍历的的链表
     *
     * @return
     */
    public List<CommodityClassify> getBFTList() {
        List<CommodityClassify> list = new LinkedList<CommodityClassify>();
        int currentIndex = 0;
        list.add(this);
        while (currentIndex < list.size()) {
            if (!list.get(currentIndex).isLeafy()) {
                list.addAll(list.get(currentIndex).getChildren());    ///将子节点添加的list中
            }
            currentIndex++;
        }
        return list;
    }

    /**
     * 深度优先遍历 非递归算法   方向 :从右到左
     */
    public void depthFirstTraversal(CommodityVisitor visitor) {
        Stack<CommodityClassify> stack = new Stack<CommodityClassify>();
        stack.push(this);
        while (!stack.isEmpty()) {
            CommodityClassify c = stack.pop();
            visitor.visit(c);
            if (!c.isLeafy()) {
                stack.addAll(c.getChildren());
            }
        }
    }

    //*************************  检索 **************************

    /**
     * 广度优先检索
     */
    public CommodityClassify breadthFirstSearch(CommoditySearcher searcher) {
        Queue<CommodityClassify> queue = new LinkedList<CommodityClassify>();
        queue.add(this);
        while (!queue.isEmpty()) {
            CommodityClassify c = queue.poll();
            if (searcher.search(c)) {
                return c;
            }
            queue.addAll(c.getChildren());
        }
        return null;
    }

    /**
     * 深度优先检索
     */
    public CommodityClassify depthFirstSearch(CommoditySearcher searcher) {
        Stack<CommodityClassify> stack = new Stack<CommodityClassify>();
        stack.push(this);
        while (!stack.isEmpty()) {
            CommodityClassify c = stack.pop();
            if (searcher.search(c)) {
                return c;
            }
            if (!c.isLeafy()) {
                stack.addAll(c.getChildren());
            }
        }
        return null;
    }


    //***************************  常见操作 函数*******************************
    /**
     * 添加子商品分类
     * @param name   分类名称
     * @param code   分类编码
     * @param amount 数量
     * @return
     */
    public CommodityClassify addChild(String name, String code, int amount) {
        CommodityClassify c = new CommodityClassify(name, code, amount);
        addChild(c);
        return c;
    }

    public CommodityClassify addChild(String name, String code) {
        CommodityClassify c = new CommodityClassify(name, code);
        addChild(c);
        return c;
    }

    public CommodityClassify getByCode(final String code) {
        CommoditySearcher vs = new CommoditySearcher() {
            public boolean search(CommodityClassify c) {
                return (c.getCode().equals(code));
            }
        };
        return depthFirstSearch(vs);
    }
    /**
     * 把 当前树 从 整棵树中 剥离出来;
     */
    public void remove() throws Exception {
        if (this.getParent() == null) throw new Exception("根节点不能删除");
        //1、找到双亲
        parent = this.getParent();
        //2、删除当前树
        parent.removeChild(this);
    }

    /**
     * 删除商品分类
     * @param cc
     * @throws Exception
     */
    public void remove(CommodityClassify cc) throws Exception {
        if (this.getParent() == null) throw new Exception("根节点不能删除");
        if (this.equals(cc)) throw new Exception("不能删除自身");
        if (!this.children.contains(cc)) throw new Exception("不包含子节点");
        removeChild(cc);
    }
    //************************  其他 ********************************************
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (obj.getClass() != this.getClass()) return false;
        CommodityClassify c = (CommodityClassify) obj;
        return c.getCode().equals(this.getCode());
    }

    public Object clone() throws CloneNotSupportedException {
        super.clone();
        CommodityClassify c = new CommodityClassify(name, code, amount);
        List<CommodityClassify> ccList = Collections.synchronizedList(new LinkedList<CommodityClassify>());
        for (CommodityClassify cc : children) {
            CommodityClassify newCC = (CommodityClassify) cc.clone();
            newCC.setParent(c);
            ccList.add(newCC);
        }

        c.setChildren(ccList);
        return c;
    }
}  

  

 

 

public interface CommoditySearcher {
    public boolean search(CommodityClassify c);
}

 

 

 

public interface CommodityVisitor {
    public void visit(CommodityClassify cc);
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值