現在的大部分架構都是 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、清空購物車,返回建立的訂單對象
整個流程我們假定建立訂單就等同於客戶確認訂單,此時減少庫存。也有可能是後台確認訂單配貨後才減少庫存,這和賣家的經營策略有關。
這兩個例子裡面,商務邏輯都在模型中實現,控制器(也就是封裝應用程式邏輯的層)僅僅完成處理輸入資料、調用業務方法、反饋結果等任務。