前言
本應該繼續連載手擼框架系列文章的。但最近有一個需求 -> 優惠卷,之前很多朋友讓我出一篇優惠卷相關的文章。這不,本章應了大夥的願。開始我自己的表演 🔥🔥
額,這裏還要插一句,有很多新人感覺在使用框架的過程中根本用不到PHP的很多概念,例如abstract,final 部分人感覺protected,private 都沒有太大用處。更別提interface在框架中的使用了,感覺好無用處的舉爪~
策略模式
優惠卷的存在到消亡至少要經歷三個步驟(創建->使用->失效),以下爲優惠卷完整生命週期圖,
優惠卷有幾百種幾千種的優惠(騙人)方式(姿勢),結合PHP代碼來解決優惠卷應如何創建更合適,首先先創建一個類作爲優惠卷的模版
class UserCouponTem
{
}
這個模版則是一個樹根,未來所有優惠卷都要通過這個根去擴展,接下來創建一系列的優惠卷參數,例如與設計數據表一樣,如下所示,通過成員變量的方式,束縛了優惠卷的具體字段。
/**
* @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的統一邏輯。
}
寫好了一個簡單的策略模式,那開始寫一個策略吧。
使用策略
下方代碼創建了一個通用紅包。繼承模版類中的字段並且去實現接口create方法
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;
致謝
希望每篇文章並不是僅僅講一件問題,我會把問題的擴展思想一併告訴大家,希望可以幫助到你。謝謝