代码地址如下:
http://www.demodashi.com/demo/12834.html

前言:

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

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

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

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

实现:

说完了要实现的功能,紧接着就要去分析,咱们的MVP的架子该如何去分析呢:

首先来看M层,大家都知道M层是数据层,是操作数据的关键层,那咱们这块主要有获取商品单个商品的增减单个商品的选中取消单个店的选中取消所有商品的全选取消,V层就是显示这层了,这里就定义了几种情况,成功获取到商品显示修改时显示某个商品显示错误页面显示空的页面,P层就是两个层的桥梁了

对view层进行回调显示了。

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

从图中大家可以看得出来,首先是定义好咋们的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了,咋们可以看看它的定义:



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

代码补充说明:

项目代码比较多,这个是没办法全部贴出来,以上是模型的实现代码,具体的代码结构,见 项目结构图,以及具体的项目代码包

项目结构图:

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

代码地址如下:
http://www.demodashi.com/demo/12834.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

Mvp快速搭建商城购物车模块的更多相关文章

  1. 用JSP实现的商城购物车模块

    这两天,在学习JSP,正好找个小模块来练练手: 下面就是实现购物车模块的页面效果截图: 图1. 产品显示页面 通过此页面进行产品选择,增加到购物车 图2 .购物车页面 图3 . 商品数量设置 好了,先 ...

  2. mmall商城购物车模块总结

    购物车模块的设计思想 购物车的实现方式有很多,但是最常见的就三种:Cookie,Session,数据库.三种方法各有优劣,适合的场景各不相同.Cookie方法:通过把购物车中的商品数据写入Cookie ...

  3. Vue node.js商城-购物车模块

      一.渲染购物车列表页面 新建src/views/Cart.vue获取cartList购物车列表数据就可以在页面中渲染出该用户的购物车列表数据 data(){   return {      car ...

  4. 夺命雷公狗---DEDECMS----5快速入门之商城快速搭建实现快递方式和支付方式的显示

    我们现在用dedecms快速搭建一个商场,方法如下所示: 如此类推.写多几个栏目,效果 如下所示: 然后我们添加几个商品,记得要刷新下页面噢,不见见不到商品 添加成功后去看看效果如何: 出来了,但是如 ...

  5. 新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial

    新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial 作者:韩梦飞沙 Auth ...

  6. 利用yeoman快速搭建React+webpack+es6脚手架

    自从前后端开始分离之后,前端项目工程化也显得越来越重要了,之前写过一篇搭建基于Angular+Requirejs+Grunt的前端项目教程,有兴趣的可以点这里去看 但是有些项目可以使用这种方式,但有些 ...

  7. 9款一键快速搭建PHP运行环境的好工具

    9款一键快速搭建PHP运行环境的好工具 胡倡萌 2011/02/19 网络资源 77,063 1     内容提要: 建立一个PHP网站,首先需要搭建PHP的开发和运行环境,对于PHP初学者也是一个难 ...

  8. django 快速搭建blog

    如果本文看不懂的,去看的我视频吧!http://www.testpub.cn/ ------------------------------------------- Django 自称是“最适合开发 ...

  9. 拿nodejs快速搭建简单Oauth认证和restful API server攻略

    拿nodejs快速搭建简单Oauth认证和restful API server攻略:http://blog.csdn.net/zhaoweitco/article/details/21708955 最 ...

随机推荐

  1. CentOS6.8-minimal安装gnome桌面 安装NVC远程桌面连接

    https://blog.csdn.net/nimasike/article/details/72844403

  2. AC日记——斐波那契数列(升级版) 洛谷 P2626

    斐波那契数列(升级版) 思路: 水题: 代码: #include <cmath> #include <cstdio> #include <cstring> #inc ...

  3. C/C++下__FILE__参数过长的问题解决办法

    编译usrsctp库时,爆出一个编译问题: snprintf(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, ...

  4. 13、Django实战第13天:分页列表功能

    我们看课程 机构列表页是需要分页的 为了完成分页功能,我们需要用到Django的一个开源开发库django-pure-pagination workon mxonline pip install dj ...

  5. 洛谷 - Sdchr 的邀请赛 T1 取石子

    比赛的时候都推出来了和 质因子的指数和有关,硬是没做出来QWQ,我傻死算了 但其实这是一个结论题,因为这本来就是阶梯NIM游戏的模型.阶梯NIM游戏是指,有 n+1 阶台阶(0 ~ n),每阶上都有若 ...

  6. POJ 3537 Crosses and Crosses (NEERC)

                      Crosses and Crosses Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 4 ...

  7. [Contest20180316]Game

    这题有一个结论:如果他是最强的(⑨),那么线段树最优,如果他是最弱的,那么链状树最优 严格证明可能挺困难,感性理解就是公平赛制让强的人容易赢,极度不公平的赛制能让弱的人有机会反杀 所以我们只改他的能力 ...

  8. python之装饰器、生成器、内置函数、JSON

    一.装饰器: 装饰器,器在这里的意思是函数,也就是装饰函数.作用是给其他函数添加新功能,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了, ...

  9. iOS开发——NSIBPrototypingLayoutConstraint原型约束造成的莫名问题

    问题描述: 使用Autolayout 从xib加载后代码添加Constraint,xib中没有任何约束,只是创建了n个View并拖了线方便调用   在运行过程中产生约束冲突错误, NSIBProtot ...

  10. c# 播放mp3

    转载:http://www.cnblogs.com/igrl/archive/2010/03/29/1699975.html /// <summary> /// 播放MP3文件 /// & ...