摘要:我們可以把取消發(fā)貨單和取消訂單看成一個被觀察或被訂閱的類實(shí)例的對象,一旦發(fā)生取消行為,我們立即通知各個觀察者做出相對應(yīng)的行為。裝飾器模式裝飾器思想,不管以前業(yè)務(wù)邏輯,甚至不去讀,調(diào)用之前的接口裝飾上新的數(shù)據(jù),達(dá)到自己的目的。
前言
還是每月的目標(biāo)至少寫一篇文章,一晃八月份就要過去了,這個月依然沒有什么產(chǎn)出,毫無疑問最近的狀態(tài)就是不停的工作,不停的加班。所以還是把最近工作進(jìn)行一個總結(jié),首先來我看看這段時間我做了什么?
工作內(nèi)容這次工作的主要內(nèi)容就是“取消發(fā)貨單”功能,這個功能的上下文是這樣的:我們支付成功的訂單會在一段時間后被拆成發(fā)貨單,本次開發(fā)任務(wù)的目的就是通過客戶端對用戶開放申請取消發(fā)貨單的功能。其實(shí)這個功能就是發(fā)貨單服務(wù)生成退款單之后回調(diào)訂單服務(wù)的一系列undo操作,其次這些邏輯我們目前都是同步調(diào)用未異步隊(duì)列化,接著我們來梳理下大致有哪些undo操作:
undo訂單&訂單商品信息->undo商品庫存->undo各種促銷優(yōu)惠活動的庫存->undo錢包余額->log->消息
顯而易見這些操作基本和取消訂單的邏輯絕大多數(shù)一致,加之取消訂單的代碼已經(jīng)很老了,而且可維護(hù)性,擴(kuò)展性,可用性都很差,所以我又多了一項(xiàng)任務(wù)“重構(gòu)取消訂單”。我們接著來梳理下取消訂單的邏輯:
undo訂單&訂單商品信息->undo商品庫存->undo各種促銷優(yōu)惠活動的庫存->生成退款單->undo錢包余額->undo贈品->undo紅包->log->消息
下圖清晰的梳理了兩者操作的內(nèi)容:
通過上面我們對業(yè)務(wù)邏輯的梳理,其實(shí)這兩個功能絕大多數(shù)的邏輯是可以公用的,且這每個子邏輯都可以獨(dú)立成為一個個體,這么看來這就是典型的訂閱通知模型“觀察者模式”應(yīng)用的場景。我們可以把“取消發(fā)貨單”和“取消訂單”看成一個被觀察或被訂閱的類實(shí)例的對象,一旦發(fā)生取消行為,我們立即通知各個觀察者做出相對應(yīng)的行為。本來php是提供了觀察者的接口SplSuject和SplObserver,我們只需實(shí)現(xiàn)該接口即可,但是SplSuject的attach成員方法不支持閉包(使用閉包可以使觀察者被通知的時候再實(shí)例化,節(jié)省了一定的性能和內(nèi)存空間),所以我自己最后重新實(shí)現(xiàn)了該接口。最后我們的模型如下:
填充業(yè)務(wù)邏輯完成上面的建模,其實(shí)我們的功能其實(shí)就算完成一半了,剩下的事情就是在每個類文件填充對應(yīng)獨(dú)立的業(yè)務(wù)邏輯即可。
/** * 被觀察者接口 * * 由于php原生的被觀察者接口SplSubject不支持注冊閉包,即自己實(shí)現(xiàn)一下這個接口 */ Interface ObservableInterface { /** * 注冊觀察者對象 * * @param Closure $closure 閉包形式注冊 * @return void */ public function attach(Closure $closure); /** * 剔除觀察者對象 * * @param ObserverInterface $observer 觀察者對象 * @return void */ public function detach(ObservableInterface $observer); /** * 通知觀察者對象 * * @return void */ public function notify(); } /** * 觀察者接口 * * php原生觀察者接口SplObserver */ Interface ObserverInterface { /** * 觀察者操作 * * @param ObservableInterface $observable 被觀察者對象 * @return void */ public function operate(ObservableInterface $observable); }
/** * 取消訂單被訂閱實(shí)體 * * 被訂閱/被觀察者實(shí)體 */ class Observable implements ObservableInterface { /** * 注冊的觀察者/訂閱對象 * * @var array */ private $observers = []; /** * 已經(jīng)被通知的觀察者/訂閱對象 * * @var array */ private $hadNotify = []; /** * 構(gòu)造函數(shù) * * @return void */ public function __construct(params...) { } /** * 注冊觀察者/訂閱對象 * * @param Closure $closure 閉包形式注冊 * @return void */ public function attach(Closure $closure) { $this->observers[] = $closure; } /** * 批量注冊觀察者/訂閱對象 * * @param array $closures 閉包形式注冊 * @return void */ public function multiAttach($closures = []) { $closures = array_filter($closures, function ($var) { if ($var instanceof Closure) { return $var; } }); $this->observers = array_merge($this->observers, $closures); } /** * 剔除觀察者/訂閱對象 * * @param ObserverInterface $observer 觀察者對象/訂閱對象 * @return void */ public function detach(ObservableInterface $observer) { foreach ($this->observers as $k => $v) { if ($v() === $observer) { unset($this->observers[$k]); } } } /** * 通知觀察者/訂閱對象 * * @return void */ public function notify() { foreach ($this->observers as $v) { $instance = $v(); if (in_array($instance, $this->hadNotify, true)) { // 不通知重復(fù)的訂閱 continue; } $instance->operate($this); $this->hadNotify[] = $instance; } } }
最后我們在我們的控制器類中完成調(diào)用如下:
class OrderController { /** * 取消訂單 */ public function cancel() { try { /* 創(chuàng)建取消訂單的被觀察者 */ $subject = new Observable(); // 注冊訂單觀察者 $subject->attach(function () { return new Order(); }); // 注冊商品觀察者 $subject->attach(function () { return new Goods(); }); // 注冊促銷商品觀察者 $subject->attach(function () { return new PromotionGoods(); }); // 注冊退款單觀察者 $subject->attach(function () { return new RefundOrder(); }); // 注冊錢包觀察者 $subject->attach(function () { return new Wallet(); }); // 注冊紅包觀察者 $subject->attach(function () { return new Bonus(); }); // 注冊贈品觀察者 $subject->attach(function () { return new Gift(); }); // 注冊日志觀察者 $subject->attach(function () { return new Log(); }); // 注冊消息觀察者 $subject->attach(function () { return new Notice(); }); /* 廣播 */ $subject->notify(); } catch (Exception $e) { # code... } } } class DeliveryController { /** * 取消發(fā)貨單 */ public function cancel() { try { /* 創(chuàng)建取消發(fā)貨單的被觀察者 */ $subject = new Observable(); // 注冊訂單觀察者 $subject->attach(function () { return new Order(); }); // 注冊商品觀察者 $subject->attach(function () { return new Goods(); }); 等等(不注冊紅包和贈品觀察者)... /* 廣播 */ $subject->notify(); } catch (Exception $e) { # code... } } }
這樣的話我們完全高內(nèi)聚松耦合了我們的業(yè)務(wù)代碼,如果未來需要增加新的邏輯,我們只需要注冊新的觀察者即可。這樣重構(gòu)完成代碼后,我們未來在取消訂單的時候只需要注冊訂單的觀察者到取消訂單的被觀察者即可,其他的觀察者我們再注冊到一個異步執(zhí)行的取消訂單的被觀察者實(shí)例中,通過這樣我們就能給用戶帶來好的體驗(yàn),用戶取消訂單的操作我們只需通知訂單狀態(tài)變更,其余的觀察者我們異步通知保證最終成功,在未來實(shí)現(xiàn)這個功能時我們的業(yè)務(wù)代碼根本不需要動,只需要改變調(diào)用方式。
裝飾器模式裝飾器思想,不管以前業(yè)務(wù)邏輯,甚至不去讀,調(diào)用之前的接口裝飾上新的數(shù)據(jù),達(dá)到自己的目的。最近遇到的問題,在我們的訂單列表加一些字段,但是訂單列表的代碼基本無法閱讀和調(diào)整,最后想到了裝飾器的思想,最后我們完全不需要管之前的邏輯,我們只需調(diào)用現(xiàn)有的類方法,再裝飾上我們想要的數(shù)據(jù)即可,這樣就最簡化和快捷的達(dá)到了我們的目的。
Easy PHP:一個極速輕量級的PHP全??蚣?/pre>掃面下方二維碼關(guān)注我的技術(shù)公眾號,及時為大家推送我的原創(chuàng)技術(shù)分享
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/25693.html
摘要:曾今誰都有過迷茫期,下面是我開始開發(fā)中,不斷改變的代碼組織方式。 曾今 誰都有過迷茫期,下面是我開始PHP開發(fā)中,不斷改變的代碼組織方式。 初期:所有代碼一股腦控制器controller 曾今只是簡單的理解MVC 中期:業(yè)務(wù)代碼抽象一部分到模型層model 開始覺得model層是否該做點(diǎn)什么了 后期:業(yè)務(wù)代碼控制器,模型層只寫db的curd方法 復(fù)雜的業(yè)務(wù)代碼使contro...
摘要:這個月的計劃本來是對基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)做一個沉淀,但是,但是,但是這個月的的狀態(tài)就是工作工作既然這樣就總結(jié)下這個月的工作吧。 前言 目標(biāo)是每個月寫一篇文章,對從事編程開發(fā)的基礎(chǔ)知識做一個學(xué)習(xí)總結(jié)。這個月的計劃本來是對基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)做一個沉淀,但是,但是,但是......這個月的的狀態(tài)就是工作工作...既然這樣就總結(jié)下這個月的工作吧。 工作內(nèi)容 促銷活動的抽獎工具,具備如下功能: 根據(jù)不同...
摘要:我們今天也來做一個萬能遙控器設(shè)計模式適配器模式將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。今天要介紹的仍然是創(chuàng)建型設(shè)計模式的一種建造者模式。設(shè)計模式的理論知識固然重要,但 計算機(jī)程序的思維邏輯 (54) - 剖析 Collections - 設(shè)計模式 上節(jié)我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進(jìn)行操作,第二類是返回一個容器接口對象,上節(jié)我們介紹了...
摘要:我們今天也來做一個萬能遙控器設(shè)計模式適配器模式將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。今天要介紹的仍然是創(chuàng)建型設(shè)計模式的一種建造者模式。設(shè)計模式的理論知識固然重要,但 計算機(jī)程序的思維邏輯 (54) - 剖析 Collections - 設(shè)計模式 上節(jié)我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進(jìn)行操作,第二類是返回一個容器接口對象,上節(jié)我們介紹了...
摘要:,命令模式,將行為請求者和行為實(shí)現(xiàn)者解耦,將行為抽象為對象。解釋器模式,迭代器模式,將集合對象的存儲數(shù)據(jù)和遍歷數(shù)據(jù)職責(zé)分離。即將遍歷的責(zé)任交給迭代器返回的迭代器,迭代器。 設(shè)計模式總結(jié) 創(chuàng)建型:除了直接new來實(shí)例化對象外,提供了多種隱藏創(chuàng)建邏輯的生成對象的方法 結(jié)構(gòu)型:通過對象和類的組合,得到新的結(jié)構(gòu)和功能 行為型:解決對象之間的通行和功能職責(zé)分配 詳細(xì)分類 工廠 簡單工廠...
閱讀 1074·2021-11-22 13:53
閱讀 1626·2021-11-17 09:33
閱讀 2425·2021-10-14 09:43
閱讀 2901·2021-09-01 11:41
閱讀 2304·2021-09-01 10:44
閱讀 2974·2021-08-31 09:39
閱讀 1475·2019-08-30 15:44
閱讀 1885·2019-08-30 13:02