Mvp快速搭建商城购物车模块

作者: 的一幕 | 来源:发表于2018-04-24 17:21 被阅读57次

    前言:

    说到MVP的时候其实大家都不陌生,但是涉及到实际项目中使用,还是有些无从下手。因此这里小编带着大家一步步地如何用MVP去搭建购物车模块。

    首先还是按照惯例,用一张实现的动态图来说明吧:


    demo.gif

    看图其实可以看得出来咱们这块的功能主要有:

    • 单个店面的选择
    • 某个店面下对某个商品的选择
    • 对某个店面里某个商品数量的增减
    • 最下面的商品全选
    • 对选中的商品价格的计算
    • 对选中商品进行结算(主要给服务器那边)

    分析:

    说完了要实现的功能,紧接着就要去分析,咱们的MVP的架子该如何去分析呢:
    首先来看M层,大家都知道M层是数据层,是操作数据的关键层,那咱们这块主要有获取商品单个商品的增减单个商品的选中取消单个店的选中取消所有商品的全选取消,V层就是显示这层了,这里就定义了几种情况,成功获取到商品显示修改时显示某个商品显示错误页面显示空的页面,P层就是两个层的桥梁了
    对view层进行回调显示了。

    这里画一张结构图,来说明MVP的特点:

    购物车类结构图.png

    从图中大家可以看得出来,首先是定义好咋们的IMode接口,接口里面只有一个获取所有的商品方法:

    //需要传入数据的类型,该类承担着从网络或本地获取数据的部分
    public interface IMode<T> {
        void loadList();
    }
    

    紧接着就是咋们的ShopMode实现类了:

    //当前每次需要回调的价格变量
    private double price;
    private List<ShopCartBean> select_list = new ArrayList<>();//传到结算页面的商品数据
    private List<ShopCartBean> allShopCarBean = new ArrayList<>();//传到结算页面的商品数据
    
    //获取的数据源部分,从Asset目录下面的shopcartdata.json获取,获取成功后,将数据交给了回调接口,并且将获取到的数据放到allShopCarBean集合里面
    @Override
    public void loadList() {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            AssetManager assetManager = context.getAssets();
            BufferedReader bf = new BufferedReader(new InputStreamReader(assetManager.open("shopcartdata.json")));
            String line;
            while ((line = bf.readLine()) != null) {
                stringBuilder.append(line);
            }
            String json = stringBuilder.toString();
            Gson gson = new Gson();
            List<ShopCartBean> list = gson.fromJson(json, new TypeToken<List<ShopCartBean>>() {
            }.getType());//对于不是类的情况,用这个参数给出
            listener.loadSuccess(list);
            allShopCarBean.addAll(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    //点击了某个店面下的某个商品的数量减少, parent_position:店面的id, child_position:商品的id
    public void numberReduce(int parent_position, int child_position) {
        ShopCartBean bean = allShopCarBean.get(parent_position);
        List<GoodsBean> goodsList = bean.getGoods();
        GoodsBean goodsBean = goodsList.get(child_position);
        String goods_num = goodsBean.getGoods_number();
        int goodsNum = Integer.parseInt(goods_num);
        boolean canReduce = false;
        if (goodsNum > 1) {
            canReduce = true;
        }
        //通过id获取相应的商品
        GoodsBean selectGoodsBean = goodsNumChange(2, parent_position, child_position);
        Log.d(TAG, "goodsBean.number:" + goodsBean.getGoods_number());
        if (selectGoodsBean.isCheck() && canReduce) {
            //价格需要在前面的基础上减去单个商品的价格,相当于数量减少了一个
            price -= Double.parseDouble(selectGoodsBean.getGoods_price());
            Log.d(TAG, "price:" + price);
            listener.onNumberReduce(price, select_list);
        }
    }
    
    //商品数量的增减并且返回选中的GoodsBean
    private GoodsBean goodsNumChange(int type, int parent_position, int child_position) {
        ShopCartBean bean = allShopCarBean.get(parent_position);
        List<GoodsBean> goodsList = bean.getGoods();
        GoodsBean goodsBean = goodsList.get(child_position);
        String goods_num = goodsBean.getGoods_number();
        int goodsNum = Integer.parseInt(goods_num);
        if (type == 1) {
            goodsNum = goodsNum + 1;
        } else {
            if (goodsNum > 1) {
                goodsNum = goodsNum - 1;
            }
        }
        goodsBean.setGoods_number(String.valueOf(goodsNum));
        ShopCartBean selectBean = new ShopCartBean();
        //对当前的选中的ShopCartBean进行重新给值
        selectBean.clearGoods(bean, select_list);
        //如果之前在select_list中存在,移除之前的,将新的放到该集合中
        int index = isContainsShopBean(select_list, selectBean);
        if (index != -1) {
            select_list.remove(index);
        }
        select_list.add(selectBean);
        listener.onNumberChange(parent_position);
        return goodsBean;
    }
    
    //判断当前的shopCartBean是否在之前选中的集合中
    private int isContainsShopBean(List<ShopCartBean> existShopBeanList, ShopCartBean shopCartBean) {
        for (int i = 0; i < existShopBeanList.size(); i++) {
            ShopCartBean selectBean = existShopBeanList.get(i);
            Log.d(TAG, "selectBean.getSupplier_id" + selectBean.getSupplier_id());
            Log.d(TAG, "shopCartBean.getSupplier_id" + shopCartBean.getSupplier_id());
            if (selectBean.getSupplier_id().equals(shopCartBean.getSupplier_id())) {
                return i;
            }
        }
        return -1;
    }
    
    //点击了某一个店面,此时就是全选当前店面下的商品或是全消店面下面的商品
    public void itemChildClick(int position) {
        ShopCartBean bean = allShopCarBean.get(position);
        //如果之前存在当前的ShopCartBean则进行移除操作
        int index = isContainsShopBean(select_list, bean);
        if (index != -1) {
            select_list.remove(index);
        }
    
        boolean isSelected;
        boolean checkAll;
        //选中与未选中做取反操作
        if (bean.isCheck()) {
            isSelected = false;
        } else {
            isSelected = true;
        }
    
        //保存店铺点击状态
        bean.setCheck(isSelected);
        //通知全选CheckBox的选择状态,看是不是全选的
        if (allSelect() == allShopCarBean.size()) {
            checkAll = true;
        } else {
            checkAll = false;
        }
        //这里如果是选中了某一个店,需要对这个店下面的商品总价格加操作
        if (isSelected) {
            for (int i = 0; i < bean.getGoods().size(); i++) {
                //只有在没选中的情况下才会去修改状态以及总价格
                if (!bean.getGoods().get(i).isCheck()) {
                    bean.getGoods().get(i).setCheck(true);
                    price += Double.parseDouble(bean.getGoods().get(i).getGoods_number()) * Double.parseDouble(bean.getGoods().get(i).getGoods_price());
                }
            }
            select_list.add(bean);
        } else {
            // 解决点击取消选择商品时,店铺全选按钮取消选择状态,不会不变成全不选
            if (allChildSelect(position) == bean.getGoods().size()) {
                for (int i = 0; i < bean.getGoods().size(); i++) {
                    //只有在选中情况下才会去修改状态以及总价格
                    if (bean.getGoods().get(i).isCheck()) {
                        bean.getGoods().get(i).setCheck(false);
                        price -= Double.parseDouble(bean.getGoods().get(i).getGoods_number()) * Double.parseDouble(bean.getGoods().get(i).getGoods_price());
                    }
                }
                select_list.remove(bean);
            }
        }
        listener.onItemChildClick(price, checkAll, select_list, position);
    }
    
    //对某一个商品进行选中与未选中
    public void childClick(int parent_position, int child_position) {
        ShopCartBean bean = allShopCarBean.get(parent_position);
        ShopCartBean selectBean = new ShopCartBean();
        selectBean.clearGoods(bean, select_list);
    
        List<GoodsBean> goodsList = bean.getGoods();
        GoodsBean goodsBean = goodsList.get(child_position);
        boolean isSelected;
        boolean checkAll;
        if (goodsBean.isCheck()) {
            isSelected = false;
            price -= Double.parseDouble(goodsBean.getGoods_number()) * Double.parseDouble(goodsBean.getGoods_price());
            selectBean.getGoods().remove(goodsBean);
        } else {
            isSelected = true;
            price += Double.parseDouble(goodsBean.getGoods_number()) * Double.parseDouble(goodsBean.getGoods_price());
            selectBean.getGoods().add(goodsBean);
        }
        //保存商品点击状态
        goodsBean.setCheck(isSelected);
        //通知店铺选择的状态
        if (allChildSelect(parent_position) == goodsList.size()) {
            bean.setCheck(true);
            selectBean.setCheck(true);
        } else {
            bean.setCheck(false);
            selectBean.setCheck(false);
        }
        int index = isContainsShopBean(select_list, selectBean);
        if (index != -1) {
            select_list.remove(index);
        }
        select_list.add(selectBean);
    
        //通知全选CheckBox的选择状态
        if (allSelect() == allShopCarBean.size()) {
            checkAll = true;
        } else {
            checkAll = false;
        }
        listener.onItemChildClick(price, checkAll, select_list, parent_position);
    }
    
    //所有的店面下面所有的商品选中的操作
    public void selectAll() {
        price = 0;
        select_list.clear();
        for (int i = 0; i < allShopCarBean.size(); i++) {
            ShopCartBean shopCartBean = allShopCarBean.get(i);
    
            //选择店铺
            if (!shopCartBean.isCheck()) {
                shopCartBean.setCheck(true);
            }
            for (int j = 0; j < shopCartBean.getGoods().size(); j++) {
                //选择店铺的商品
                if (!shopCartBean.getGoods().get(j).isCheck()) {
                    shopCartBean.getGoods().get(j).setCheck(true);
                    Log.d(TAG, "数量:" + shopCartBean.getGoods().get(j).getGoods_number());
                }
                price += Double.parseDouble(shopCartBean.getGoods().get(j).getGoods_number()) * Double.parseDouble(shopCartBean.getGoods().get(j).getGoods_price());
            }
            select_list.add(shopCartBean);
        }
        listener.onSelctAll(price, select_list);
    }
    
    //取消全选的操作
    public void unSelectAll() {
        if (allSelect() == allShopCarBean.size()) {
            for (int i = 0; i < allShopCarBean.size(); i++) {
                ShopCartBean shopCartBean = allShopCarBean.get(i);
    
                if (shopCartBean.isCheck()) {
                    shopCartBean.setCheck(false);
                }
                for (int j = 0; j < shopCartBean.getGoods().size(); j++) {
                    if (shopCartBean.getGoods().get(j).isCheck()) {
                        shopCartBean.getGoods().get(j).setCheck(false);
                    }
                }
            }
            select_list.clear();
            price = 0;
            listener.onUnSelectAll(price, select_list);
        }
    }
    
    //某个店面下,某个商品数量加的操作
    public void numberAdd(int parent_position, int child_position) {
        GoodsBean goodsBean = goodsNumChange(1, parent_position, child_position);
        if (goodsBean.isCheck()) {
            price += Double.parseDouble(goodsBean.getGoods_price());
            listener.onNumberAdd(price, select_list);
        }
    }
    

    关于mode层的业务逻辑就是这么多了,下面就是搭建p层了,看下p层的接口:

    public interface Presenter {
    
        public void presenterList();
    
    }
    

    这里就定义了一个方法,主要是去看下它的子类:

    public class ShopCarPresenter implements IPresenter, ShopLoaderListener {
        //持有view层的接口,需要v层传进来
        IView view;
        //持有mode层的接口,此处在该类直接生成
        Mode mode;
    
        public ShopCarPresenter(Context context, IView view) {
            this.view = view;
            this.mode = new ShopMode(context, this);
        }
    }
    

    其实对于p层有两种操作,一种是不对view层进行回调的操作,一种是需要对view层进行回调,由于这里分两种情况,因此这里就举例说明:

    //看到没就是这么简单的一句,不带回调到view层的
    @Override
    public void presenterList() {
        mode.loadList();
    }
    
    //也是一句,调用了ShopCartFragment的方法
    @Override
    public void onNumberAdd(double price, List<ShopCartBean> select_list) {
        if (view instanceof ShopCartFragment) {
            ((ShopCartFragment) view).numberAdd(price, select_list);
        }
    }
    

    总的来说,p层是我们最简单的一层,因为它只是建立view层和mode层的桥梁,持有他们的实例。

    下面再来看看view层的定义,看下接口:

    public interface IView<T> {
        public void showSuccessPage(List<T> list);
    
        public void showSuccessPage(T t);
    
        public void showErrorPage();
    
        public void showEmptyPage();
    }
    

    这里方法就根据自己业务写方法了,其实我这里也是没必要定义那么多方法的,真正用到了就上面两个方法。

    咋们这里view层的实例就是ShopCartFragment了,咋们可以看看它的定义:


    ShopCartFragment类定义.png

    其实就是对Iview实现,然后在不同的实现方法里面处理view,所以在view的实现类里面不会出现处理业务的代码,只会跟view相关的代码。

    项目结构图:

    结构图.png

    代码传送门

    相关文章

      网友评论

        本文标题:Mvp快速搭建商城购物车模块

        本文链接:https://www.haomeiwen.com/subject/eurjlftx.html