從零開始單排學設計模式「裝飾模式」黑鐵 I
閱讀本文大概需要 3.6 分鐘。
本篇是設計模式系列的第四篇,雖然之前也寫過相應的文章,但是因為種種原因後來斷掉了,而且發現之前寫的內容也很渣,不夠系統。
所以現在打算重寫,加上距離現在也有一段時間了,也算是自己的一個回顧吧!
學而時習之,不亦說乎。
推薦閱讀:
目前段位: 黑鐵 I
Let's Go!
前言
設計模式不是語法,是一種巧妙的寫法,能把程式變的更加靈活。架構模式比設計模式大,架構模式是戰略,而設計模式是戰術。
設計模式分為3大型別:建立型,行為型,結構型,總共有23種。
裝飾模式
裝飾模式(Decorator)指的是在不必改變類檔案和使用繼承的情況下,動態地擴充套件一個物件的功能。它是透過建立一個包裝物件,也就是裝飾來包裹真實的物件。
這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。
業務需求
公司接到一個任務,需要為某平臺開發一個搭配不同服飾的小專案,比如類似QQ、網路遊戲或論壇都有的Avatar系統(為了簡化程式碼,直接使用控制檯模擬)。
程式碼實現
經過公司的慎重討論(實際就幾秒鐘),開發這一個專案的重任,又當仁不讓的被產品經理交給了我,我:臉上笑嘻嘻,心裡MMP。發一下下的小牢騷,不過還是抓緊幹活。
思索一下,該系統要為不同的人進行裝扮,所以定義一個人的類,不用每次裝扮其他人時修改該類的程式碼。
然後人身上要有很多的服飾,比如:大T恤、垮褲、鞋子等等,然後穿上之後,需要展示出來。所以這裡的話,可以抽象出一個服飾的基類,然後各個具體的服飾都繼承該基類即可。
程式碼如下:
Person類
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public void show() {
System.out.println("裝扮者:" + name);
}
}
服裝抽象類
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Finery extends Person {
protected Person component;
/**
* 打扮
* @param component
*/
public void decorate(Person component){
this.component = component;
}
@Override
public void show() {
if(null != component){
component.show();
}
}
}
具體服飾類
/**
* @author: LKP
* @date: 2019/2/16
*/
public class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
}
}
class BigTrouser extends Finery {
@Override
public void show() {
System.out.println("垮褲");
}
}
class Sneakers extends Finery{
@Override
public void show() {
System.out.println("破球鞋");
}
}
class LeatherShoes extends Finery{
@Override
public void show() {
System.out.println("皮鞋");
}
}
class Tie extends Finery{
@Override
public void show() {
System.out.println("領帶");
}
}
class Suit extends Finery{
@Override
public void show() {
System.out.println("西裝");
}
}
這裡內部類,只是為了較少程式碼量,實際開發中可不要偷懶,按實際來建立。
客戶端程式碼
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Main {
public static void main(String[] args) {
Person person = new Person("孤獨鍵客");
System.out.println("第一種裝扮:");
Finery tShirts = new TShirts();
Finery bigTrouser = new BigTrouser();
Finery sneakers = new Sneakers();
tShirts.show();
bigTrouser.show();
sneakers.show();
person.show();
System.out.println("\n第二種裝扮:");
Finery suit = new Suit();
Finery tie = new Tie();
Finery leatherShoes = new LeatherShoes();
suit.show();
tie.show();
leatherShoes.show();
person.show();
}
}
程式碼簡單搞定,接下來來看一下執行結果
搞定收工,審視一下,自我感覺還算不錯,如果新裝扮只需改變一下呼叫順序即可,如果又新人物,只需重新new一個Person類就可以了。
接下里將專案提交上傳,然後告訴leader一聲,over,離下班時間還早,好像還可以做點其他的事情~。
正當你準備開啟去幹點其他事情,leader回覆你了:
leader:“你仔細看看這段程式碼,這樣寫意味著什麼?
你想象一下,是不是把‘大T恤’、‘垮褲’、‘破球鞋’、‘裝扮者’一個一個詞顯示出來,是不是相當於你光著身子,一個一個把這些穿上,這可有點像脫衣舞哦~”。
我:“你意思是,這些應該都在內部組裝完畢,然後在顯示出來?”。
leader:"賓果,而且還要按照正確的順序串聯起來控制,這裡有點難度,修改好之後再給我"。
這似乎和某種設計模式有關,難道是建造者模式嗎?不對,建造者模式要求建造的過程必須是穩定的,而這個穿搭的過程是不固定的,一個有個性的人又無數種方案。
經過一番查詢,這恰恰最適合用裝飾模式了。
我們修改一下具體的服飾類
/**
* @author: LKP
* @date: 2019/2/16
*/
public class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
super.show();
}
}
class BigTrouser extends Finery {
@Override
public void show() {
System.out.println("垮褲");
super.show();
}
}
class Sneakers extends Finery{
@Override
public void show() {
System.out.println("破球鞋");
super.show();
}
}
class LeatherShoes extends Finery{
@Override
public void show() {
System.out.println("皮鞋");
super.show();
}
}
class Tie extends Finery{
@Override
public void show() {
System.out.println("領帶");
super.show();
}
}
class Suit extends Finery{
@Override
public void show() {
System.out.println("西裝");
super.show();
}
}
再修改一下客戶端程式碼:
/**
* @author: LKP
* @date: 2019/2/16
*/
public class Main {
public static void main(String[] args) {
Person person = new Person("孤獨鍵客");
System.out.println("第一種裝扮:");
Sneakers sneakers = new Sneakers();
BigTrouser bigTrouser = new BigTrouser();
TShirts tShirts = new TShirts();
sneakers.decorate(person);
bigTrouser.decorate(sneakers);
tShirts.decorate(bigTrouser);
tShirts.show();
System.out.println("第二種裝扮:");
LeatherShoes leatherShoes = new LeatherShoes();
Tie tie = new Tie();
Suit suit = new Suit();
leatherShoes.decorate(person);
tie.decorate(leatherShoes);
suit.decorate(tie);
suit.show();
}
}
第二版的程式寫完了,來測試一下
完美搞定,哈哈,我還可以換種裝飾方式
看下結果
光著膀子、打著領帶、下身垮褲、腳上皮鞋,絕對的極具個性。
最後,完美搞定,提交程式碼~~~
裝飾模式UML類圖
總結
來總結一下裝飾模式:
主要解決 :一般的,我們為了擴充套件一個類經常使用繼承方式實現,由於繼承為類引入靜態特徵,並且隨著擴充套件功能的增多,子類會很膨脹。
何時使用 :在不想增加很多子類的情況下擴充套件類。
如何解決 :將具體功能職責劃分,同時繼承裝飾者模式。
關鍵程式碼 : 1、Component 類充當抽象角色,不應該具體實現。 2、修飾類引用和繼承 Component 類,具體擴充套件類重寫父類方法。
應用例項 : 1、孫悟空有 72 變,當他變成"廟宇"後,他的根本還是一隻猴子,但是他又有了廟宇的功能。 2、不論一幅畫有沒有畫框都可以掛在牆上,但是通常都是有畫框的,並且實際上是畫框被掛在牆上。在掛在牆上之前,畫可以被蒙上玻璃,裝到框子裡;這時畫、玻璃和畫框形成了一個物體。
優點 :裝飾類和被裝飾類可以獨立發展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動態擴充套件一個實現類的功能。
缺點 :多層裝飾比較複雜。
使用場景 : 1、擴充套件一個類的功能。 2、動態增加功能,動態撤銷。
注意事項 :可代替繼承。
往期精彩回顧
我被程式設計師坑了600萬致公司倒閉,當事人逐條反駁:這鍋我不背
歡迎關注我的公眾號「程式設計師的成長之路」,閱讀更多精彩!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69902700/viewspace-2636182/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從零開始單排學設計模式「策略模式」黑鐵 II設計模式
- 從零開始單排學設計模式「簡單工廠設計模式」黑鐵 III設計模式
- 從零開始單排學設計模式「UML類圖」定級賽設計模式
- 從零開始學設計模式(七)—橋接模式設計模式橋接
- 我學設計模式 之裝飾模式設計模式
- 設計模式——裝飾模式設計模式
- 設計模式-裝飾模式設計模式
- 設計模式學習-裝飾模式,橋接模式設計模式橋接
- 設計模式-裝飾設計模式設計模式
- Java學設計模式之裝飾器模式Java設計模式
- 設計模式----裝飾器模式設計模式
- 設計模式-裝飾者模式設計模式
- 設計模式——裝飾者模式設計模式
- 設計模式-裝飾器模式設計模式
- [設計模式] 裝飾器模式設計模式
- 設計模式(八):裝飾模式設計模式
- 【設計模式之裝飾模式】設計模式
- 設計模式之裝飾模式設計模式
- [設計模式]裝飾者模式設計模式
- 裝飾模式(裝飾設計模式)詳解——小馬同學@Tian設計模式
- 《從零開始學Swift》學習筆記(Day 63)——Cocoa Touch設計模式及應用之單例模式Swift筆記設計模式單例
- 裝飾設計模式設計模式
- 軟體設計模式學習(十三)裝飾模式設計模式
- 小白設計模式:裝飾者模式設計模式
- 設計模式--裝飾模式(Decorator Pattern)設計模式
- 設計模式系列之「裝飾模式」設計模式
- 設計模式(八)裝飾器模式設計模式
- 設計模式-裝飾模式(Decorator Pattern)設計模式
- 設計模式之-裝飾器模式設計模式
- 極簡設計模式-裝飾模式設計模式
- GoLang設計模式21 - 裝飾模式Golang設計模式
- 設計模式之【裝飾器模式】設計模式
- 設計模式(六):裝飾器模式設計模式
- 設計模式之裝飾者模式設計模式
- 設計模式 (十)裝飾模式(Decorator)設計模式
- 【大話設計模式】——裝飾模式設計模式
- java設計模式--裝飾器模式Java設計模式
- 設計模式——從HttpServletRequestWrapper瞭解裝飾者模式設計模式HTTPServletAPP