裝飾者模式 想看本系列前作的朋友可以點擊下麵鏈接哦。 一起去開心的購物吧——淺談觀察者模式 記一場精彩的籃球比賽——淺談策略模式 大家好,又跟大家見面啦,今天呢,我與大家分享一個新的Java設計模式——裝飾者模式。 首先,不能免俗的我們來看一下官方給的定義: 裝飾者模式動態地將責任附加到對象上。若要 ...
裝飾者模式
聲明:本文為原創,如有轉載請註明轉載與原作者並提供原文鏈接,僅為學習交流,本人才識短淺,如有錯誤,敬請指正
想看本系列前作的朋友可以點擊下麵鏈接哦。
一起去開心的購物吧——淺談觀察者模式
記一場精彩的籃球比賽——淺談策略模式
大家好,又跟大家見面啦,今天呢,我與大家分享一個新的Java設計模式——裝飾者模式。
首先,不能免俗的我們來看一下官方給的定義:
裝飾者模式動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
通過這個官方定義,我們也許還理不清這是一個怎麼樣的設計模式,但是大家肯定都會覺得這絕對是一個非常靈活的適合後期維護的設計模式,為什麼呢,短短的一句話中,我們發現了動態,擴展功能,更有彈性這些令人激動的詞語(至少對維護一群“屎山”代碼的程式員來說足夠讓人激動),同時,這個設計模式還直接diss了Java中一個非常普遍的概念,繼承,這時候也許就會有支持“繼承”的擁躉出來吶喊:憑什麼這麼說我家愛豆,她發高燒50度還在堅持構建對象,實在是太偉大了。OKOK,稍後我們會說明原因滴,此處我們先表下不提。
最近有一款游戲呢非常的火爆,他就是風暴英。。咳咳(風暴要火),他就是APEX,作為一款吃雞類型的游戲,她承接了從H1Z1到絕地求生到各種吃雞手游的熱度,可以說目前是非常的火爆,對於這種類型的游戲,相信各位看官不會感到陌生,不少人估計更是忠實玩家,在這種開局一個人,裝備全靠撿的游戲中,擁有一把好槍無疑是勝利的最佳保障(伏地魔除外,苟就完事了),而一把好槍,除了槍本身之外,還有眾多的組件可供搭配,從消音器到瞄準鏡再到握把,將不同的組件組裝到一把槍中,最終就可以擁有一把威力強大的好槍。
裝飾者模式便是實現了這樣的功能。
在裝飾者模式中,有著兩個最重要的角色,一個稱為裝飾者,另一個稱為被裝飾者,被裝飾者通過裝飾者“裝飾”自己,而裝飾者可以在被裝飾者的行為之前或之後加上自己的行為,已達到特定的行為目的。
那麼現在是時候開始我們的吃雞之旅了。在游戲中,被裝飾者就是“槍”。我們首先定義一個被裝飾者介面,用於定義被裝飾者的行為。
public interface Gun { String getName(); String showPower(); }
第一個方法用於返回槍的名稱,隨著組件的增加,槍的名稱會發生變化。第二個方法用於展示當前槍的威力,當然我們是用一句話來形容而不是真的開一槍。
接下來我們定義一個裝飾者介面,即各種組件的介面
public interface Unit extends Gun{ @Override String getName(); }
此處,我們發現,組件介面繼承了槍介面,並且會重寫Gun中的getName方法,這裡我們可以得出結論,在裝飾者模式中,裝飾者和被裝飾者對象有相同的超類型!
然後我們該定義幾個具體被裝飾者了,在這裡,我們會定義M16與98K兩種型號的槍充當具體被裝飾者
public class _98K implements Gun { private String power = "一把威力巨大的98K"; private String name = "98K"; @Override public String getName() { return name; } @Override public String showPower() { return power; } }
public class M16 implements Gun { private String power = "一把射速很快的M16"; private String name = "M16"; @Override public String getName() { return name; } @Override public String showPower() { return power; } }
兩個具體被裝飾者大同小異,不再贅述。
然後是我們的幾個具體組件對象,此處呢,我們定義了三種組件以供搭配——八倍鏡,擴容彈夾,握把。
public class Grip implements Unit { private Gun gun; private String function = ",加裝握把,提高射擊穩定性"; private String name = "握把"; public Grip(Gun gun){ this.gun = gun; } @Override public String getName() { return gun.getName() + "+" + name; } @Override public String showPower() { return gun.showPower() + function; } }
我們仔細來看這個握把的具體實現類,我們發現,它維護了一個被裝飾者的引用,併在構造方法中將其初始化,隨後實現介面定義的方法,在調用被裝飾者的方法時,我們還夾帶了一點私貨,還記得上面的話嗎:裝飾者可以在被裝飾者的行為之前或之後加上自己的行為,已達到特定的行為目的!在這裡,我們真正實現了“裝飾”這一步。
同樣得,還有八倍鏡組件以及擴容彈夾組件
public class SightTelescope implements Unit { private Gun gun; private String name = "八倍鏡"; private String function = ",加上八倍鏡,射擊更加精準"; public SightTelescope(Gun gun){ this.gun = gun; } @Override public String getName() { return gun.getName() + "+" + name; } @Override public String showPower() { return gun.showPower() + function; } }
public class ExpansionCartridgeClip implements Unit { private Gun gun; private String name = "擴容彈夾"; private String function = ",換裝擴容彈夾,絕對火力壓制"; public ExpansionCartridgeClip(Gun gun){ this.gun = gun; } @Override public String getName() { return gun.getName() + "+" + name; } @Override public String showPower() { return gun.showPower() + function; } }
至此,我們已經成功定義了我們所有的裝飾者與被裝飾者,趕快開始這一局緊張刺激的吃雞吧。我們的裝飾者模式將在游戲中經受考驗。
public class Game { public static void main(String[] args) { Gun _98k = new _98K(); show(_98k); _98k = new ExpansionCartridgeClip(_98k); show(_98k); _98k = new SightTelescope(_98k); show(_98k); Gun m16 = new M16(); show(m16); m16 = new Grip(m16); show(m16); m16 = new ExpansionCartridgeClip(m16); show(m16); m16 = new SightTelescope(m16); show(m16); } private static void show(Gun gun){ System.out.println("擁有了" + gun.getName() + "\n" + gun.showPower()); } }
我們首先創建了98k的對象,使用列印方法查看它的狀態,然後我們的裝飾者,也就是組件開始對98k進行裝飾,我們正在組裝一把威力強大的98K,有人也許想問,為啥new出來的組件對象可以直接賦值給98k對象呢,別忘了,裝飾者模式的關鍵,裝飾者和被裝飾對象有著相同的超類型。
同樣的,我們使用組件裝飾了一把m16步槍,是時候開火了,讓我們看看到底這些槍有沒有按照我們的想法正常工作呢?
duang,就像加了許多特技,我們的槍再也不用裸奔了,他現在是擁有很多組件的大殺器,是時候送快遞大吉大利,今晚吃雞了。
如果我們喜歡,還可以再加上很多的組件,只要它實現了裝飾者介面並按照正確的方式實現,我們就可以在運行時動態的,不限量地使用它來裝飾對象,而且不用修改原有的代碼,對象可以在任何時候被裝飾,只要它的確是一個被裝飾者(實現了被裝飾者的介面),而這些,都是單純的繼承無法實現的,這也就是為什麼我們開頭所說,裝飾者提供了比繼承更具有彈性的方案。這個模式再次著重表現了我們的一個設計原則——對修改關閉,對擴展開放!
感謝大家聽我絮絮叨叨這麼久,那麼裝飾者模式的淺談就先進行到這裡,不說了,我先吃雞去了(^O^)