Mvp快速搭建商城购物车模块
前言:
说到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快速搭建商城购物车模块
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
Mvp快速搭建商城购物车模块的更多相关文章
- 用JSP实现的商城购物车模块
这两天,在学习JSP,正好找个小模块来练练手: 下面就是实现购物车模块的页面效果截图: 图1. 产品显示页面 通过此页面进行产品选择,增加到购物车 图2 .购物车页面 图3 . 商品数量设置 好了,先 ...
- mmall商城购物车模块总结
购物车模块的设计思想 购物车的实现方式有很多,但是最常见的就三种:Cookie,Session,数据库.三种方法各有优劣,适合的场景各不相同.Cookie方法:通过把购物车中的商品数据写入Cookie ...
- Vue node.js商城-购物车模块
一.渲染购物车列表页面 新建src/views/Cart.vue获取cartList购物车列表数据就可以在页面中渲染出该用户的购物车列表数据 data(){ return { car ...
- 夺命雷公狗---DEDECMS----5快速入门之商城快速搭建实现快递方式和支付方式的显示
我们现在用dedecms快速搭建一个商场,方法如下所示: 如此类推.写多几个栏目,效果 如下所示: 然后我们添加几个商品,记得要刷新下页面噢,不见见不到商品 添加成功后去看看效果如何: 出来了,但是如 ...
- 新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial
新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial 作者:韩梦飞沙 Auth ...
- 利用yeoman快速搭建React+webpack+es6脚手架
自从前后端开始分离之后,前端项目工程化也显得越来越重要了,之前写过一篇搭建基于Angular+Requirejs+Grunt的前端项目教程,有兴趣的可以点这里去看 但是有些项目可以使用这种方式,但有些 ...
- 9款一键快速搭建PHP运行环境的好工具
9款一键快速搭建PHP运行环境的好工具 胡倡萌 2011/02/19 网络资源 77,063 1 内容提要: 建立一个PHP网站,首先需要搭建PHP的开发和运行环境,对于PHP初学者也是一个难 ...
- django 快速搭建blog
如果本文看不懂的,去看的我视频吧!http://www.testpub.cn/ ------------------------------------------- Django 自称是“最适合开发 ...
- 拿nodejs快速搭建简单Oauth认证和restful API server攻略
拿nodejs快速搭建简单Oauth认证和restful API server攻略:http://blog.csdn.net/zhaoweitco/article/details/21708955 最 ...
随机推荐
- linux ssh 登录服务器失败,密码明明没错【解决】
本来这样登录的: $ ssh 123.123.123.123 //ssh + IP 然后输入密码就是登录不了,显示permision denied 后来使用如下方式登录,成功! $ ssh -v us ...
- 【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律
转自:http://www.cnblogs.com/kevince/p/3887827.html 首先声明一下,这里的规律指的是循环,即找到最小循环周期. 这么一说大家心里肯定有数了吧,“不就是nex ...
- python——入门系列(一)索引与切片
1.索引和切片:python当中数组的索引和其他语言一样,从0~n-1,使用索引的方法也是中括号,但是python中的切片的使用简化了代码 索引:取出数组s中第3个元素:x=s[2] 切片:用极少的代 ...
- hdu1823(二维线段树模板题)
hdu1823 题意 单点更新,求二维区间最值. 分析 二维线段树模板题. 二维线段树实际上就是树套树,即每个结点都要再建一颗线段树,维护对应的信息. 一般一维线段树是切割某一可变区间直到满足所要查询 ...
- luogu P1026 统计单词个数
题目链接 luogu P1026 统计单词个数 题解 贪心的预处理母本串从i到j的最大单词数 然后dp[i][j] 表示从前i个切了k次最优解 转移显然 代码 #include<cstdio&g ...
- 【动态规划】【记忆化搜索】CODEVS 3415 最小和 CodeVS原创
f(l,r,i)表示第i段截第l位到第r位时,当前已经得到的价格最小值,可以很显然地发现,这个是没有后效性的,因为对之后截得的段都不造成影响. 注意水彩笔数=1的特判. 递归枚举当前段的r求解(∵l是 ...
- 1.2(Spring MVC学习笔记) Spring MVC核心类及注解
一.DispatcherServlet DispatcherServlet在程序中充当着前端控制器的作用,使用时只需在web.xml下配置即可. 配置格式如下: <?xml version=&q ...
- 启用多处理器编译--加快VS2013编译
依次打开项目“属性“==>”配置属性“==>”C/C++(或其它语言)“==>”常规“,最后一项,多处理器编译选择是. 官方解释如下: /MP 选项在命令行上以减少总时间编译源文件. ...
- TELNET终端类型选项
转:http://www.cnpaf.net/Class/Telnet/200408/5.html 1. 命令名称及编号TERMINAL-TYPE242.命令含义IACWILLTERMINAL-TYP ...
- 使用spring-boot-admin对spring-boot服务进行监控
原文:http://www.cnblogs.com/ityouknow/p/8440455.html 上一篇文章<springboot(十九):使用Spring Boot Actuator监控应 ...