iT邦幫忙

2022 iThome 鐵人賽

DAY 9
0
自我挑戰組

設計模式探索系列 第 9

[Day 9] 裝飾器模式 (1)

  • 分享至 

  • xImage
  •  

前言

終於進入了第三章─ 裝飾器模式!首先可以稍微回顧一下第一章提到的其中一個原則─ 多用"組合",少用"繼承",這章會以物件組合的方式,避免繼承濫用的問題,並可以在執行期間對物件進行裝飾!至於這裡的裝飾指的是什麼,請繼續看下去...

類別大爆炸!

本章舉的例子是一個具有各種咖啡的點餐系統,乍看之下跟第一章的各種鴨子有點像,不過是變成了各種自由發揮的咖啡!可以看到最基本的咖啡是具有描述與價格的...
https://ithelp.ithome.com.tw/upload/images/20220924/20140096GdrVkKAZa6.png

但咖啡每個人可以自由加入各種調味品,例如牛奶、糖、冰量、不同的咖啡豆等,每個人愛好的份量也不同 (雙份、摩卡、去冰...),此時該怎麼處理呢?既然這些咖啡都擁有的一樣的attributes─敘述與價格,一樣最無腦的繼承一波!(然後就爆炸了...)
https://ithelp.ithome.com.tw/upload/images/20220924/20140096rJfuZQz3WQ.png

要如何改良呢?書本給出一種改良的寫法...
https://ithelp.ithome.com.tw/upload/images/20220924/201400967gXrC0xYgE.png

但有一些明顯的缺點,(又是大家來找碴時間XD)例如如果牛奶價格改變,我們就必須在每個飲料類別中去修改cost()的計算方式,不符合封裝概念!又或者這種架構,也無法動態調整份量,例如要加雙倍的牛奶,照原本的寫法就必須變成多一個doubleMilk屬性?又或者需要把布林值改成整數數值...

但感覺還有更好的方法...例如我今天要的只是最基本的"黑咖啡",這個物件類別卻需要繼承各種我永遠不會想要加的配料......

不妨想想看你會如何設計呢?設計在這個情境中會有哪些缺點?
我自己第一時間則是想到第一章鴨子的case,想把不變的部分拉出來,變化的部份封印起來,這樣是不是應該抽出一些糖度、冰量、咖啡的class?例如這樣...
https://ithelp.ithome.com.tw/upload/images/20220924/201400961hXmou23Eb.png
至於有何問題,跟裝飾器模式比起來有何異同,可以明天再比較看看!

接下來就要介紹裝飾器模式登場了...除此之外,來看看另外一條登場的原則,以及裝飾器模式如何實踐!

第五個原則

延伸之前的第三個原則,我們已經知道繼承會造成行為在編譯時就固定,而組合則能帶來在執行期彈性變化的效果,除了改變原本的內容,甚至可以擴展其他原本沒有的部分,且不會動到原本封裝起來的部分。這就點出了一個重要的原則:

類別應該歡迎擴展,但拒絕修改

原本程式經過驗證的部分,我們不希望改變它,因此拒絕修改,但為了保持彈性,因應不斷的變化,我們希望可以輕易地去擴展原本的類別,這樣就可以讓我們的程式更加地穩固,卻又不僵化。

策略模式中,最後的類別圖就是使用 "組合" 而非繼承來達成這個好處;另外前面的觀察者模式也拒絕修改subject的部分,但卻又可以自由地新增observer來進行擴展;接下來的裝飾器模式,一樣可以看到實踐了這個原則,讓我們繼續看下去...

  • 註:書中也有提醒,不是所有情境都需要強硬地應用每一條原則,因為這也可能讓程式變得更複雜,所以我們應該做的是關注那些最有可能改變的地方,然後在這些地方應用這幾條原則去進行設計。

上一篇
[Day 8] 觀察者模式 (3)
下一篇
[Day 10] 裝飾器模式 (2)
系列文
設計模式探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言