設計模式之死磕裝飾器模式(原創)

2021-09-20 01:56:15 字數 3569 閱讀 2681

前言:

在談論裝飾器模式之前,先談乙個筆者曾經遇到過的問題。遊戲sdk(對遊戲sdk開發不了解的話可以參考android遊戲sdk詳解 這篇文章)分為兩種,一種是渠道sdk(渠道sdk這個概念可以參考剛才的文章)還有一種叫聚合sdk。那麼,什麼是聚合sdk?簡單點理解聚合sdk,其實就是把各個渠道同功能的介面統一歸納為乙個介面,例如a公司的登入介面為asdk.login( ) 、 b公司的登入介面為bsdk.login( ) 、c公司的登入介面為csdk.login( )等以此類推。然後聚合sdk開發目的就是要把這些不同渠道的介面統一成自己渠道家的聚合介面。比如,自己家的聚合登入介面為mysdk.login( ) ,那遊戲方接入渠道sdk時只需要呼叫我們的mysdk.login( ) 介面即可內部呼叫對應的渠道sdk。那麼,聚合sdk的設計原則是什麼?

首先我們從現象去分析,因為渠道sdk有很多家,但是自己家的聚合sdk只能設計一套,所以聚合sdk的設計首先應該是偏向頂層設計。而且,前面也說了,聚合sdk只需要提供一套統一的api,裡面去實現具體的渠道sdk,所以,它一般會被設計成抽象類或者介面。可能你對上面的論述聽的雲裡霧裡,沒關係,這裡只是提到我曾經遇到過的問題。那麼,本篇文章介紹的裝飾器模式就可以成為聚合sdk的一種設計思路。

什麼是裝飾器模式?

關於這一種設計模式比較官方的解釋是:裝飾器模式(decorator pattern)允許向乙個現有的物件新增新的功能,同時又不改變其結構。這種型別的設計模式屬於結構型模式(關於結構性模式的概念,可以參考 設計模式概念與簡介 這裡面詳細介紹了這一概念),它是作為現有的類的乙個包裝。這種模式建立了乙個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。

裝飾器模式應用場景:

假設我們現在按照抖音上的熱門配方想去奶茶店配置一杯焦糖奶茶,這杯奶茶可以根據我們自己的喜歡新增加布丁、青稞等等。現在我們要計算調製這樣一杯網紅奶茶花了多少錢,那麼通過**的方式思考應該如何去做?

首先在不考慮設計模式的情況下,如果按照傳統的編碼思路,我們會先寫乙個抽象的焦糖奶茶基類、接著焦糖奶茶基類若不能滿足我的需要(基本上不滿足),比如要在奶茶的基礎上加青稞,我們就會寫乙個焦糖青稞奶茶類去繼承焦糖奶茶基類,返回新的**(附加青稞的**);比如我現在又不想要青稞(客戶的需求總是很難滿足吶 ~),想要加布丁,那麼我們就會又寫乙個焦糖布丁奶茶去繼承奶茶基類、後面的以此類推。雖然這種方法可以解決問題,但是這樣層層繼承,子類會比較膨脹,耦合性太強。

那麼,我們換一種思路,既然這杯焦糖奶茶有多種可新增材料,但是它的本質依舊是一杯奶茶,新增的材料只是它附加的一種屬性。按照物件導向的思想,既然附加的材料屬性有很多,那麼我們就可以將材料屬性單獨抽取成乙個父類材料物件(也就是先不管奶茶,只針對附加的材料,這樣做的好處是低耦合,解決子類過於膨脹的問題),讓各種各樣的材料分別繼承材料基類即可;因此我們也就可以這樣定義,焦糖奶茶就是我們的核心元件、布丁和青稞以及別的材料是我們的裝飾者。

綜上,我們可以首先定義乙個頂層的介面,這個介面(主要是針對奶茶進行操作)定義的行為規範如:這杯奶茶花了多少錢,使用了什麼材料,於是乎就有了以下**

頂層介面

剛才也說了,附加的多種材料,我們可以單獨把它抽象出來,將其設計成乙個抽象類,讓子類去設計定義具體的材料(使用的是青稞還是布丁)。但是,這個材料基類單獨定義沒有任何意義,需要將材料 放進奶茶中才能完成**的需求(計算的是總價)。因此,這個基類需要實現最頂層的奶茶介面,然後通過建構函式,將頂層介面進行賦值操作。可能你會問,為什麼要將頂層介面通過建構函式進行賦值操作,因為只有賦值操作以後,才可以再次呼叫頂層介面裡面的方法:

材料基類

介面和基類已經簡單介紹和封裝完了。那麼接下來我們就來定義上面提到的角色。

首先是焦糖奶茶,剛才說了,焦糖奶茶是這個功能的核心元件,而且我們也定義了最頂層的奶茶介面,所以,焦糖奶茶只需要實現頂層介面,在裡面進行賦值返回操作即可,假設這杯不含任何材料的純粹焦糖奶茶價值12毛幣,那麼就有以下**:

核心元件 - 焦糖奶茶

定義完了奶茶,我們在定義客戶可能想要在裡面新增的青稞,布丁等等。因為在上面我們已經定義了新增材料的基類,現在只需要繼承材料基類然後在子類設定附加材料的**就可以滿足計算**以及統計材料的任務:

附加材料 - 布丁

附加材料 - 青稞 

焦糖奶茶附加材料青稞和布丁都已經準備好了,下面就等著新增測試使用了。

下面就開始測試這杯網紅奶茶的**(老闆我現在要布丁以及雙份的青稞)

新增多種材料的總價測試

下面是僅單獨新增一種材料的結果測試:

新增一種材料的結果測試

為了加深對裝飾器模式的印象,這裡在舉乙個網上的例子:

在英雄聯盟中,有個叫提莫的英雄。他是負責瓦羅蘭大陸的班德爾城安全的偵察兵首領,我們知道英雄公升級以後系統會賦予新的技能點供英雄去學習,那麼這種英雄學技能的現象我們用裝飾器模式又該如何去設計操作?

跟上面的網紅奶茶一樣,我們把 「提莫學技能」 分成兩部分,第一部分就是我們的核心元件,也就是我們的提莫英雄;第二部分我們把提莫的技能抽取共性,成為核心元件的裝飾。

首先,我們定義頂層英雄學習技能的介面:

頂層介面

接著,我們抽象技能的屬性,讓子類自己實現:

技能類父類

我們先例項化提莫物件:

例項化提莫

接著,輪到提莫開始學技能啦:

提莫學技能

為了方便測試,我把提莫的技能名稱放在了建構函式這裡,下面就是測試:

測試結果

總結:

裝飾器模式是繼承的一種替代模式,其優點是可以動態擴充套件乙個實現類的功能。這種設計模式下不僅可以擴充套件乙個類的功能,也可以動態增加功能,動態撤銷。但缺點就是多層裝飾使用起來相對比較複雜。本質是將具體功能職責劃分(例如區分核心元件以及附加屬性職責)減少子類直接繼承父類的耦合性。

如果這篇文章對你有幫助,希望各位看官留下寶貴的star,謝謝。

設計模式之死磕工廠模式(原創)

工廠模式 factory pattern 是開發中比較常用的設計模式之一。這種型別的設計模式屬於建立型模式 關於建立型模式的概念,可以參考 設計模式概念與簡介 簡單點理解就是建立物件的模式,比如使用頻率最高的單例模式就是建立型模式的一種 其中工廠模式仔細區分的話,可以分為三種,分別是簡單工廠模式 工...

設計模式 裝飾器模式

裝飾器模式 decorator pattern 允許向乙個現有的物件新增新的功能,同時又不改變其結構。這種型別的設計模式屬於結構型模式,它是作為現有的類的乙個包裝。這種模式建立了乙個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。public inte ce playe...

設計模式 裝飾器模式

裝飾者模式的應用場景 裝飾者模式 decorator pattern 是指在不改變原有物件的基礎之上,將功能附加到物件上,提供了比繼承更有彈性的替代方案 擴充套件原有物件的功能 屬於結構型模式。裝飾者模式在我們生活中應用也比較多如給煎餅加雞蛋 給蛋糕加上一些水果 給房子裝修等,為物件擴充套件一些額外...