代码地址如下:
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. php多台服务器实现session共享

    使用Redis存储Session(前提是服务期间已实现redis共享,可参照:laravel项目使用twemproxy部署redis集群) 修改php.ini: session.save_handle ...

  2. 用LoopBack搭建RESTful 风格的API

    1.安装node.NPM 2.安装strongloop npm install -g --unsafe-perm install strongloop 3.创建工作目录并且配置loopback应用 m ...

  3. java异常基本知识

    Throwable     |--Error     |--Exception         |--RuntimeException                异常体系的特点:异常体系中的所有类 ...

  4. 1087: Common Substrings (哈希)

    1087: Common Substrings Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/ ...

  5. Proxmox VE

    Proxmox虚拟化环境是基于QEMU/KVM和LXC的开源服务器虚拟化管理解决方案.我们可以使用集成的易于使用的WEB界面或通过CLI管理虚拟机,容器,高可用集群,存储和网络. Proxmox VE ...

  6. go时间转化

    将string转化为time.Time layout := "2006-01-02 15:04:05" str := "2017-11-24 15:10:22" ...

  7. 五角数 Exercise06_01

    /** * @author 冰樱梦 * 题目:五角数 * 时间:2018年下半年 * * */ public class Exercise06_01 { public static void main ...

  8. Git学习笔记(一) 安装及版本库介绍

    安装Git 最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑.不过,慢慢地有人把它移植到了Windows上.现在,Git可以在Linux.Unix.Mac和 ...

  9. React Conf 2017 干货总结 1: React + ES next = ♥

    React Conf 2017在加利福尼亚州的圣克拉拉万豪酒店圆满落幕,这已经是Facebook举办的第三届React官方大会了.虽然不能参会,但是作为前端开发者,我们当然不能错过这个绝佳的学习契机. ...

  10. 【FTP】java FTPClient 文件上传内容为空,文件大小为0

    问题:如题所述,使用FTPClient上传至FTP服务器, 表现如下:①文件大小为0 ②上传很小的文件,但是要花费很长的时间,20K要花费2分钟甚至更久 ③没有任何的报错,没有任何的乱码 解决方法: ...