C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?
作者:junjie 发布时间:2022-06-25 12:34:55
现在的大部分框架都是 MVC 模式,但 MVC 三个部分怎么配合,这里做了一点总结:
基本原则:业务逻辑代码应该写在 M 里面,而应用程序逻辑应该写在 C 里面。V 只是单纯的展示数据。
举个简单例子吧:用户往购物车添加一个商品
用户点击商品的“添加到购物车”按钮,引起一次请求。服务器开始处理该请求,过程:
1、检查当前用户是否有权限(比如是否已经登录、用户帐户状态、是否可以购物等)
2、检查要添加的商品ID是否有效、
3、检查要添加的商品库存是否足够
4、将商品加入购物车,并保存购物车状态
5、反馈信息
在上述流程中:
1: 是应用程序逻辑(一般由框架实现):因为和“添加商品到购物车”这个业务没有直接关系
2: 业务逻辑:不能购买不存在的商品,这是业务进行的基本条件
3: 业务逻辑:商品库存决定了是否可以购买此商品,这是业务进行的基本条件
4: 业务逻辑
5: 应用程序逻辑
用代码表示的,可能像下面这样:
// Cart控制器
class Controller_Cart
{
function actionAddGoods()
{
$goods_id = (int)$_GET['goods_id'];
Cart::instance()->add($goods_id)->save();
echo '添加成功';
}
}
// Cart 模型
class Cart
{
/**
* 购物车中的所有项目
*/
public $items = array();
/**
* 单子模式,返回购物车对象的唯一实例
*/
static function instance()
{
...
}
function add($goods_id, $quantity = 1)
{
$goods = Goods::find($goods_id)->get();
// 检查 id 和库存数
if ($goods->id && $quantity > $goods->remaining)
{
// 添加商品到购物车
$this->items[] = array($goods, $quantity);
}
else
{
throw new CartExecption('无效的商品 ID');
}
return $this;
}
}
这个代码不完整,但是演示了最重要的部分,就是应用程序逻辑和业务逻辑的分离。
如果这个流程走下去,用户要结算了,那么代码如下:
class Controller_Cart
{
function actionCheckOut()
{
Cart::instance()->checkout();
echo '成功';
}
}
class Cart
{
function checkout()
{
// 开启一个数据库事务
....
try
{
// 创建一个新的订单对象
// $this->owner 是当前购物车的所有者(用户)
$order = new Order($this->owner);
// 将购物车中的所有商品添加到订单中
foreach ($this->items as $item)
{
list($goods, $quantity) = $item;
$order->add($goods, $quantity);
}
// 保存订单
$order->save();
// 清空购物车
$this->items = array();
}
catch (Exception $ex)
{
// 出错了,回滚事务
....
// 再重新抛出异常
throw $ex;
}
// 返回新建的订单
return $order;
}
}
class Order extends Model
{
public $items;
function add($goods, $quantity)
{
$this->items[] = array($goods, $quantity);
return $this;
}
function save()
{
foreach ($this->items as $item)
{
list($goods, $quantity) = $item;
// 保存订单时,减少订单中每一个商品的库存数
$goods->decrRemaining($quantity);
}
// 调用父类的保存
parent::save();
return $this;
}
}
结算的代码很容易理解:
1、调用购物车的 checkout() 方法
2、开启数据库事务,这样当保存订单失败时(例如库存数不够)则回滚,确保数据库内容没有受影响
3、将购物车中的所有商品添加到订单
4、调用订单对象的 save() 方法
4.1、遍历订单的所有项目,减少商品的库存(如果此时失败,商品的 decrRemaining() 方法会抛出异常)
4.2、调用模型父类的 save() 方法
5、清空购物车,返回新建的订单对象
整个流程我们假定创建订单就等同于客户确认订单,此时减少库存。也有可能是后台确认订单配货后才减少库存,这和卖家的经营策略有关。
这两个例子里面,业务逻辑都在模型中实现,控制器(也就是封装应用程序逻辑的层)仅仅完成处理输入数据、调用业务方法、反馈结果等任务。


猜你喜欢
- springboot集成 redispom文件<dependency> <groupId>
- 最近由于公司业务,就开始研究微信开发的流程,说实话,这东西刚开始看到时候和看天书的一样,总算,看了一天的文档,测试代码终于出来了。1、首先需
- 今天我们来编写一个缩放效果的ImageView ,网上有很多人都讲了这些。但有许多人都直接使用了库文件,那么我们今天做的是直接上代码编写一个
- springmvc 自定义注解 以及自定义注解的解析一、自定义注解名字@Target({ElementType.TYPE, ElementT
- 本文实例讲述了C#将Json解析成DateTable的方法。分享给大家供大家参考。具体实现方法如下:#region 将 Json 解析成 D
- 本文实例为大家分享了android实现选项卡功能,通过计算偏移量,设置tetxview和imageView的对应值,一些color的值读者自
- 单元测试单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法
- 一、前言在学习分治算法之前,问你一个问题,相信大家小时候都有存钱罐的经历,父母亲人如果给钱都会往自己的宝藏中存钱,我们每隔一段时间都会清点清
- Eureka注册中心/服务发现框架Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中
- 研发背景公司安全部目前针对内部系统的网络访问日志的安全审计,大部分都是T+1时效,每日当天,启动Python编写的定时任务,完成昨日的日志审
- 打开首页,明显看到链接是https打头,https和http的通信协议差别,在于https安全性更高:http和https的差别很明显,二者
- 本文实例讲述了Java上传文件进度条的实现方法。分享给大家供大家参考,具体如下:东西很简单,主要用到commons-fileupload,其
- 1.会话会话: 用户打开了一个浏览器,点击了很多超链接,访问多个web次元,关闭浏览器,这个过程可以称之为会话有状态会话: 带有访问记录的会
- java list,set,map,数组间的相互转换详解1.list转setSet set = new HashSet( new Array
- 一.前提1.栈的内存原理图2.JVM是怎么运行方法的???1.在运行阶段的时候,classLoader类加载器会把class文件中方法对应的
- 前言自从 2017 年 C# 7.0 版本开始引入声明模式和常数模式匹配开始,到 2022 年的 C# 11 为止,最后一个板块列表模式和切
- 说起EventTrigger事件触发器,它的使用可以说是无处不在,EventTrigger继承了很多的事件接口,这些接口对我们开发是十分有用
- Struts2 * Struts2 * 的概念和Spring Mvc * 一样。1.Struts2 * 是在访问某个Action或Actio
- 本文实例为大家分享了Java实现打字游戏的具体代码,供大家参考,具体内容如下新建一个项目,然后在src里面建一个MyGame.java文件,
- 静态代理: 由我们开发者自己手动创建或者在程序运行前就已经存在的代理类,静态代理通常只代理一个类, * 是代理一个接口下的多个实现类。动态