邏輯代碼增減需求,讓我們來解耦,維護更輕鬆

  • 前言
產品的需求千變萬化,有時候需要在原有代碼邏輯上增加需求,或者 刪除,或者修改。

  1. addMeiqucickOrder 第一次 簡單的新增一個訂單
  2. addmeiquickorderBeforeValidate 第二次變化, 在新增訂單前驗證一堆判斷,至少20個判斷
  3. addMeiquickOrderWithNoRepeat 第三次變化,在驗證前,增加一個防止併發的重新新增問題
  • 貢獻
如果有更好的辦法解耦,請在評論區貼上博客鏈接哦,互相討論O(∩_∩)O哈哈~!
  • 產品需求變化了三次
需求1:商家 --> 訂單修改 --> 保存運單號 --> 修改訂單狀態爲發貨

需求2: 商家 --> 訂單修改 --> 判斷 訂單異常信息(未退款,未取消 等狀態)--> 保存運單號 --> 修改訂單狀態爲發貨

需求3: 商家 --> 訂單修改 --> 判斷 訂單異常信息(未退款,未取消 等狀態)--> 保存運單號 --> 修改訂單狀態爲發貨 --> 記錄訂單狀態修改的日誌

前景分析

從上面的需求可以看出,前後需求三次變化,

需求 1 與 需求 2 對比:在保存運單號前,先判斷訂單異常信息 才能修改

需求2 與 需求3 對比:在修改訂單爲發貨狀態時,增加記錄訂單狀態修改日誌

普遍程序員做法

把 整個流程 從頭到尾 都是 這樣寫

function updateOrderExpressNo(OrderModel $order, $expressNo) {

//先判斷  

if else if else if else ....

    //修改運單號

  $order->express_no = $expressNo;

   //增加日誌

  Log::info('訂單修改了發貨狀態:'.$order->id);

  //修改訂單狀態

  $order->status = '1'; //1爲發貨狀態

$order-save();

}

普遍程序員做法分析:

此時 增加了我們調試難度,把所有邏輯都放到一個函數裏面寫,也不確保每個功能是否完整是否能運行正常,隨着以後項目越做越大,這時只能重構。

我的做法,解耦過程如下

我們先分析以下 需求1共有2個步驟

1.保存運單號

2.訂單發貨狀態修改

//以下代碼 基於laravel5框架實現

//定義兩個行爲接口,分別是上面兩個

interface UpdateOrderExpressNoInterface {

 //修改訂單運單號接口

  public function handle($order, $expressNo);

}

interface UpdateOrderStatusInterface {

//修改訂單狀態接口

public function handle($order, $status);

}



//兩個行爲類

//修改運單號行爲

class UpdateOrderExpressNo implements UpdateOrderExpressNoInterface {

   public function handle($order, $expressNo){

     $order->express_no = $expressNo;

     return $order->save();

   }

}



//修改訂單狀態行爲

class UpdateOrderStatus implements UpdateOrderStatusInterface {

   public function handle($order, $status){

     $order->status = $status;

     return $order->save();

   }

}

//新建一個AppBehaviorProvider

class AppBehaviorProvider extends ServiceProvider
{

    /**行爲類接口
     * @var array
     */
    protected $behaviorArr = [
        //運單號修改, 啥意思呢?當我們要調用app(UpdateOrderExpressNoInterface::class) 就會得到 new UpdateOrderExpressNo 的實例對象
        UpdateOrderExpressNoInterface::class => UpdateOrderExpressNo::class,
        //修改訂單狀態
        UpdateOrderStatusInterface::class => UpdateOrderStatus::class,
     ];

    public function boot()
    {

    }
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {

        foreach ($this->behaviorArr as $interface => $class)
        {
            $this->app->bind($interface, $class);
        }
    }
}
//訂單操作控制器

class OrderController {

  protected $orderService;

  public function __construct(OrderService $orderService){

   $this->orderService = $orderService;

  }  

 public function updateExpressNo(int $orderId, Request $request){

    $status = $this->orderService->updateExpressNo($orderId, $request->input('express_no', ''));

   return $status;

 }

}

//訂單服務

class OrderService {

protected $orderModel;
protected $updateOrderExpressNo;
protected $updateOrderStatus;

  public function __construct(
    OrderModel $orderModel,
    UpdateOrderExpressNoInterface $updateOrderExpressNo,
    UpdateOrderStatusInterface $updateOrderStatus
  ){

    $this->orderModel = $orderModel;
    $this->updateOrderExpressNo = $updateOrderExpressNo;
    $this->updateOrderStatus = $updateOrderStatus;
  }  

  public function find($id){

   return $this->orderModel->find($id);

  }

  public function updateExpressNo($orderId, $expressNo)

  {

  //開啓事務,此處省略

   $order = $this->find($orderId);

     //執行修改運單號動作

     //$result = app(UpdateOrderExpressNoInterface::class)->handle($order, $expressNo);
     $result = $this->updateOrderExpressNo->handle($order, $expressNo);

    if ($result) {

    //執行修改訂單狀態動作

      //$result1 = app(UpdateOrderStatus::class)->handle($order, 1); //1爲發貨狀態
      $result1 = $this->updateOrderStatus->handle($order, 1); //1爲發貨狀態

   }

  //失敗保存則回滾,此處省略

  }

接下來我們先分析以下 需求2共有三個步驟

1. 判斷訂單狀態

2. 保存運單號

3. 訂單發貨狀態修改

//2,3步驟不變,在原有的保存運單號接口上,增加步驟1, 增加一個判斷訂單狀態的行爲類

class UpdateOrderBeforeValidate implements  UpdateOrderExpressNoInterface{

protected $updateOrder;

//這裏laravel自動幫我們new UpdateOrderExpressNo()並傳入到 構造函數了

public function __construct(UpdateOrderExpressNo $updateOrder) {

  $this->updateOrder = $updateOrder;

}

   public function handle($order, $expressNo){

     if ($order->refund != 0) {

        return '訂單退款狀態,無法保存訂單運單號';

    }else if ($order->cancle != 0){

        return '訂單取消狀態,無法保存運單號';

   }

    return $this->updateOrder->handle($order, $expressNo);

   }

}

//增加保存運單號前需要驗證的 行爲類時,需要修改AppBehaviorProvider定義的修改運單號接口對應的類,也就是告訴laravel,當控制器需要 修改運單號時,切換 UpdateOrderBeforeValidate類。

class AppBehaviorProvider extends ServiceProvider
{

    /**行爲類接口
     * @var array
     */
    protected $behaviorArr = [
       //從UpdateOrderExpressNo類 切換 UpdateOrderBeforeValidate類
        UpdateOrderExpressNoInterface::class => UpdateOrderBeforeValidate::class,
        //修改訂單狀態
        UpdateOrderStatusInterface::class => UpdateOrderStatus::class,
     ];

    public function boot()
    {

    }
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {

        foreach ($this->behaviorArr as $interface => $class)
        {
            $this->app->bind($interface, $class);
        }
    }
}

需求1 -> 需求2分析

需求2,增加了UpdateOrderBeforeValidate類,無需修改 UpdateOrder這個類,也就是對這個類修改的關閉,其他類也無需要改,並且 在該類 通過構造函數實例UpdateOrder類,並且增強 他的handle方法,裝飾者模式。

至於需求三,分析共以下步驟:

1. 訂單狀態判斷

2. 修改訂單運單號

3. 修改訂單狀態爲發貨狀態

4. 記錄日誌

//代碼就不一一列舉了,解題思路:

//增加一個 UpdateOrderStatusAfterLog類,該類用來記錄日誌,通過裝飾者模式,在構造函數傳入pdateOrderStatus類實例.

public handle($order, $status) {

  Log::info('訂單狀態修改爲:'.$order->id.':'.$status);

   return $this->updateOrderStatus->handle($order, $status);

}

//接着在 AppBehaviorProvider 修改UpdateOrder::class 爲UpdateOrderStatusAfterLog::class

備註:

__construct(OrderService $orderService) 。laravel自動給你 new OrderService() 傳入到構造函數裏面

__construct(UpdateOrderExpressNoInterface $updateOrderExpressNo)

因爲我們在provider裏面註冊了

$this->app->bind(UpdateOrderExpressNoInterface::class, UpdateOrderExpressNo::class);

告訴我們的容器,當需要UpdateOrderExpressNoInterface的接口實現類時,我們就new UpdateOrderExpressNo()傳到構造函數裏面。這是laravel的容器+依賴注入的特性。

當然在provider註冊了,需要在 config/app.php 的providers鍵下增加 AppBehaviorProvider::class, 告訴laravel自動引入這個服務提供者。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章