什麼樣的設計纔是最好的設計?
別問,問就是自己去體會…
背景
PM同學組織了一場關於下單流程業務系統拆分的需求評審,整體功能爲可線上售賣視頻課,用戶買完課之後可在線學習、不同的課程還包含線下實地培訓等、學習完之後在線考試,頒發合格證書。
實際上,該需求可分爲兩個部分來看
- 售賣:通過各種渠道把各種各樣的商品賣出去
- 履約:完成不同商品與之對應的履約流程
已有的實現
從上圖可以清晰的看到,左側爲售賣的各種商品,右側爲商品與之對應的履約流程。
同時,每個商品對應一條獨立的履約流程,商品之間可能存在相同的履約環節。
有什麼問題?
有什麼問題得看從什麼角度看
如果從業務的角度看當然沒啥問題,因爲它能滿足業務需求。
但是,從系統設計角度看,存在如下幾個問題
- 要上架售賣新品類的商品,需要定製實現對應的履約流程
- 已有商品履約流程調整,系統也需要做對應調整
- 履約流程中的履約環節缺少複用性
業務抽象建模
從上圖中,可以看出如下幾個改動點
- 抽象了一個履約規則層,不同的商品對應不同的履約規則
- 由履約規則串聯起商品下單與訂單履約,實現下單與履約的解耦
- 訂單履約模塊可隨意組合,以此完成履約流程
相對與之前的設計,核心變更如下所示:
有哪些好處?
通過這樣的調整,好處很明顯,完美的解決掉之前的問題
- 上架新品類商品,無需對應開發與之的履約流程,新增履約配置即可
- 已有商品履約流程調整,系統無需對應調整,只需修改履約配置即可
- 因爲實現瞭解耦,下單與履約相對獨立,互不影響,履約部分可提供各種各樣的履約單元組合實現履約流程
聊聊面向對象設計
面向對象的四大特性
- 封裝: 獨立模塊只暴露對外接口,封裝內部實現
- 抽象: 例如上面抽象出來業務需求表象之下的履約規則層
- 繼承: 實現通用邏輯抽取,所有子類具有父類已實現的功能
- 多態: 代碼易擴展的利器,基於接口而不基於實現編程
面向對象的六大設計原則
- SRP 單一職責原則:每一個類、模塊儘量做到職責單一
- OCP 開閉原則:對擴展開放,對修改關閉
- LSP 裏式替換原則:即子類能夠替換父類對象出現的任何地方,並且保證原來程序的邏輯行爲不變或者說正確性不被破壞
- DIP 依賴倒置原則:高層模塊不依賴低層模塊,它們共同依賴同一個抽象。抽象不要依賴具體實現細節,具體實現細節依賴抽象
- ISP 接口隔離原則:意思即一個類不應該被強迫依賴它不需要的接口,即接口設計的時候不應該大而全,可做好分類,多使用接口組合
- LOD 迪米特法則:核心在於降低類的耦合;不該有直接依賴關係的類之間,不要有依賴;有依賴關係的類之間,儘量只依賴必要的接口。迪米特法則是希望減少類之間的耦合,讓類越獨立越好。每個類都應該少了解系統的其他部分。一旦發生變化,需要了解這一變化的類就會比較少。
其他還有
- DRY原則(Don’t Repeat Yourself)
- KISS原則(Keep It Simple and Stupid)
- YAGNI原則(You Ain’t Gonna Need It)
最後一個,我個人喜歡叫做不要加戲原則。
設計模式
設計模式更多的在於解決具體問題,我的體會是不要去套模式,多去思考怎麼樣去實現代碼纔會是最優解,當你這麼做了之後,設計模式自然而然就會從你的代碼裏涌現出來。
幾年前翻了一遍《Head first 設計模式》一書,翻完的第一感受就是原來很多設計模式在實際代碼中都用過,原來每個套路還有對應的名字…
曾經整理了一個設計模式的系列文章,分別用Java與Javascript實現,在這裏:設計模式系列文章
最後
工作得越久,越會不自覺的思考,十年一線老碼農相對與工作四五年的正走上軌道且精力旺盛的生力軍的核,心競爭力在哪裏?
可能就在於系統建模能力與面向對象設計能力上?
在於哪些東西技術上能行,而實際上坑很深,敢於有所爲有所不爲上?
不在於實現一個功能的快慢,而在於後續的持續迭代與維護成本上?
軟件開發說簡單也簡單,說複雜也複雜,複雜到無法量化精確評估它的好壞!
什麼樣的設計纔是最好的設計?
別問,問就是自己去體會…