通用系統設計之優惠卷

clipboard.png

前言

本應該繼續連載手擼框架系列文章的。但最近有一個需求 -> 優惠卷,以前不少朋友讓我出一篇優惠卷相關的文章。這不,本章應了大夥的願。開始我本身的表演 🔥🔥mysql

額,這裏還要插一句,有不少新人感受在使用框架的過程當中根本用不到PHP的不少概念,例如abstract,final 部分人感受protected,private 都沒有太大用處。更別提interface在框架中的使用了,感受好無用處的舉爪~redis

策略模式

優惠卷的存在到消亡至少要經歷三個步驟(建立->使用->失效),如下爲優惠卷完整生命週期圖,sql

clipboard.png

優惠卷有幾百種幾千種的優惠(騙人)方式(姿式),結合PHP代碼來解決優惠卷應如何建立更合適,首先先建立一個類做爲優惠卷的模版數據庫

class UserCouponTem
{
}

這個模版則是一個樹根,將來全部優惠卷都要經過這個根去擴展,接下來建立一系列的優惠卷參數,例如與設計數據表同樣,以下所示,經過成員變量的方式,束縛了優惠卷的具體字段。json

/**
 * @var $couponName
 * @content 優惠券名稱
 */
public $couponName;

/**
 * @var $alidityv
 * @content 有效期
 */
public $alidityv;

/**
 * @var $userId
 * @content 綁定的用戶編碼
 */
public $userId;

/**
 * @var $price
 * @content 抵扣金額
 */
public $price;

/**
 * @var $type
 * @content 類型 0 通用紅包 1 查看擴展字段
 */
public $type;

/**
 * @var $extend
 * @content 擴展字段
 */
public $extend;

/**
 * @var $numbers
 * @content 卷號
 */
public $number;

/**
 * @var $content
 * @content 卷內容
 */
public $content;

優惠卷的模版建立完成後,接下來須要建立兩個方法,第一個爲服務提供者,規定每一個建立優惠卷的類都必須存在create方法,沒錯,這是在寫一個策略模式。數據結構

interface CouponInterface
{
    public function create($userId, $price);
}

public function provider(CouponInterface $coupon, $userId, $price)
{
    return $coupon->create($userId, $price);
}

最後是一個消費者框架

public function consumer($number)
{
    // $number 是卷號,這裏通常都是操做redis,mysql的統一邏輯。
}

寫好了一個簡單的策略模式,那開始寫一個策略吧。ide

使用策略

下方代碼建立了一個通用紅包。繼承模版類中的字段而且去實現接口create方法this

class Current extends UserCouponTem implements CouponInterface
{
    public function create($userId, $price)
    {
        $this->couponName = "通用紅包";
        $this->alidityv   = "2019-01-09";
        $this->content    = "這是一個通用紅包";
        $this->userId     = $userId;
        $this->price      = $price;
        $this->type       = 0;
        $this->extend     = [];
        $this->number     = '123456';
        
        return $this;
    }
}

最後經過下方代碼建立一個通用紅包,得到完整的一個優惠卷實例,最後將參數插入到數據庫與用戶表綁定則完成了一個基本的編碼

$userCouponTem = new UserCouponTem();
$current       = $userCouponTem->provider(new Current(), $this->request->user_id,
$this->request->price);

設計思想

部分人會懷疑這種設計是畫蛇添足,直接將邏輯設計到數據表不就OK了嘛?咱們爲什麼還要經過模版類,接口,服務提供者、服務容器去返回一個優惠卷實例?

試想不可能一次性將全部優惠卷的類型所有想到而且設計出來,數據表結構也不能頻繁去更改。如何讓一批代碼適應整個業務而且對將來業務可擴展?這樣的話則不能把全部邏輯存放到數據表中。這樣作可能有如下幾點好處

  • 可擴展性強,可以應對各類優惠卷的表達方式
  • 可維護性強,若是有新類型的業務可直接經過服務容器注入
  • 代碼優雅,便於閱讀,不管是新入職員工仍是他人都很容易讀寫優惠卷的代碼(比較優惠卷的業務實際很複雜)

上述實際就是Laravel的服務提供者、服務容器的概念,不明白的童鞋可去看文檔並參考本例子。

數據結構

僅供參考(不是太認真的設計)
用戶優惠卷表

CREATE TABLE `member_coupon` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用戶編碼',
  `number` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '卷號',
  `content` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '卷內容',
  `price` decimal(8,2) NOT NULL COMMENT '金額',
  `alidityv` datetime NOT NULL COMMENT '到期時間',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '-1 過時 0 未使用 1 已使用',
  `use_date` int(11) NOT NULL DEFAULT '0' COMMENT '使用時間',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

優惠卷記錄表

CREATE TABLE `coupon_record` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用戶編碼',
  `number` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '卷號',
  `price` decimal(8,2) NOT NULL COMMENT '金額',
  `json_content` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '具體json信息',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

致謝

但願每篇文章並非僅僅講一件問題,我會把問題的擴展思想一併告訴你們,但願能夠幫助到你。謝謝

相關文章
相關標籤/搜索