生活随笔
收集整理的這篇文章主要介紹了
装饰模式——初学JAVA设计模式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄 一、基本概念 二、簡單實例 實例一、變形金剛 實例二、喜羊羊與灰太狼 類圖 方式一:半透明模式 方式二:半透明模式+透明模式 三、透明模式和半透明模式的區別 四、小結
一、基本概念
裝飾模式是一種用于替代繼承的技術,它通過一種無須定義子類的方式來給對象動態增加職責,使用對象之間的關聯關系取代類之間的繼承關系。
裝飾模式(Decorator)定義:動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更靈活。
模式角色
Component(抽象構件類) :定義了對象的接口,可以給這些對象動態增加職責(方法),是具體構建和抽象裝飾類的共同父類,聲明了具體構件中需要實現的方法。
ConcreteComponent(具體構件類) :定義了具體的構建對象,實現了在抽象構建中聲明的方法,裝飾器可以給他增加額外的方法。
Decorator(抽象裝飾類) :是抽象構建類的子類,用于具體構件增加職責。
ConcreteDecorator(具體裝飾類) :是抽象裝飾類的子類,負責增添加新的職責。
二、簡單實例
實例一、變形金剛
類圖
代碼實現
package com
. transform
; public interface Transform { public void move ( ) ;
}
接口中定義move()方法,具體構件類必須實現此方法。
package com
. transform
;
public final class Car implements Transform { public Car ( ) { System
. out
. println ( "變形金剛是一輛車!" ) ; } @Override public void move ( ) { System
. out
. println ( "在陸地上移動" ) ; }
}
package com
. transform
;
public class Changer implements Transform { private Transform transform
; public Changer ( Transform transform
) { this . transform
= transform
; } @Override public void move ( ) { transform
. move ( ) ; }
}
package com
. transform
;
public class Robot extends Changer { public Robot ( Transform transform
) { super ( transform
) ; System
. out
. println ( "變成機器人" ) ; } public void say ( ) { System
. out
. println ( "你tm說話啊!" ) ; }
}
package com
. transform
;
public class Robot extends Changer { public Robot ( Transform transform
) { super ( transform
) ; System
. out
. println ( "變成機器人" ) ; } public void say ( ) { System
. out
. println ( "你tm說話啊!" ) ; }
}
package com
. transform
;
public class Client { public static void main ( String
[ ] args
) { Transform camaro
; camaro
= new Car ( ) ; camaro
. move ( ) ; System
. out
. println ( "-------------------------" ) ; Robot bumblebee
= new Robot ( camaro
) ; bumblebee
. move ( ) ; bumblebee
. say ( ) ; }
}
結果截圖
實例二、喜羊羊與灰太狼
題目: “喜羊羊逃命”游戲:喜羊羊被灰太狼追,喜羊羊最多5條命,灰太狼每咬到喜羊羊一次,喜羊羊就要少一條命。在逃的過程中喜羊羊可以吃到三種蘋果,吃“紅蘋果”可以給喜羊羊加上保護罩,吃“綠蘋果”可以加快喜羊羊奔跑速度,吃“黃蘋果”可以使喜羊羊趟著水跑。應用裝飾模式,用JAVA控制臺應用程序實現該設計。繪制該模式的UML圖。 提示:這個例子如果用類的繼承來實現的話那可就麻煩了,你需要為喜羊羊派生321=6個子類(有保護罩的喜羊羊,奔跑速度加快的喜羊羊,會趟水的喜羊羊,既有保護罩又會趟水的喜羊羊,奔跑速度快且會趟水的喜羊羊,有保護罩且奔跑速度快的喜羊羊,有保護罩、奔跑速度快且會趟水的喜羊羊),如果使用裝飾模式的那就不用派生諸多子類了,當喜羊羊每吃到一個蘋果,我們就用裝飾模式給喜羊羊加一個動態增加一個新功能即可。
類圖
方式一:半透明模式
實質方式一是以構造方法注入方式實現,方式二通過調用子類新添加的方法實現。
代碼實現
package sheep
;
abstract class Appearance { public int lives
; public abstract void display ( ) ;
}
package sheep
;
public final class Sheep extends Appearance { public String name
; public Sheep ( String name
) { this . name
= name
; } public void setlives ( int lives
) { this . lives
= lives
; } @Override public void display ( ) { System
. out
. println ( name
+ "的狀態:" ) ; }
}
package sheep
;
public class Decorator extends Appearance { protected Appearance appearance
; public void Decorate ( Appearance appearance
) { this . appearance
= appearance
; this . lives
= appearance
. lives
; } @Override public void display ( ) { if ( appearance
!= null
) { appearance
. display ( ) ; } }
}
package sheep
;
public class GreenApple extends Decorator { @Override public void display ( ) { appearance
. lives
= lives
; super . display ( ) ; System
. out
. println ( "吃了綠蘋果,具有加速技能,生命值為" + appearance
. lives
) ; }
}
package sheep
;
public class RedApple extends Decorator { @Override public void display ( ) { this . appearance
. lives
= lives
; super . display ( ) ; System
. out
. println ( "吃了紅蘋果,具有保護罩技能,生命值為" + appearance
. lives
) ; }
}
還有一個具體裝飾類,YellowApple代碼省略…
package sheep
;
public class WolfAtack extends Decorator { @Override public void display ( ) { super . display ( ) ; this . appearance
. lives
= appearance
. lives
- 1 ; System
. out
. println ( ) ; System
. out
. println ( "----------------------------------" ) ; System
. out
. println ( "被狼咬了一口,生命值-1,生命值為" + appearance
. lives
) ; System
. out
. println ( "----------------------------------" ) ; System
. out
. println ( ) ; }
}
package sheep
;
public class Client { public static void main ( String
[ ] args
) { Sheep sheep
= new Sheep ( "喜羊羊" ) ; sheep
. setlives ( 5 ) ; Decorator redApple
, greenApple
, yellowApple
; Decorator wolf
= new WolfAtack ( ) ; redApple
= new RedApple ( ) ; redApple
. Decorate ( sheep
) ; wolf
. Decorate ( redApple
) ; wolf
. display ( ) ; greenApple
= new GreenApple ( ) ; greenApple
. Decorate ( redApple
) ; wolf
. Decorate ( greenApple
) ; wolf
. display ( ) ; yellowApple
= new YellowApple ( ) ; yellowApple
. Decorate ( greenApple
) ; yellowApple
. display ( ) ; }
}
結果截圖
方式二:半透明模式+透明模式
代碼實現
package sheet
;
abstract class Appearance { public int lives
; public abstract void display ( ) ;
}
package sheet
;
public final class Sheep extends Appearance { public String name
; public Sheep ( String name
) { this . name
= name
; } public void setlives ( int lives
) { this . lives
= lives
; } @Override public void display ( ) { System
. out
. println ( name
+ "的狀態:" ) ; }
}
package sheet
;
public class Decorator extends Appearance { protected Appearance appearance
; public Decorator ( Appearance appearance
) { this . appearance
= appearance
; this . lives
= appearance
. lives
; } @Override public void display ( ) { appearance
. display ( ) ; }
}
具體裝飾類:只寫GreenApple類省略了YellowApple和RedApplle代碼
package sheet
;
public class GreenApple extends Decorator { public GreenApple ( Appearance appearance
) { super ( appearance
) ; } @Override public void display ( ) { this . appearance
. lives
= lives
; super . display ( ) ; System
. out
. println ( "吃了綠蘋果,具有加速技能,生命值為" + appearance
. lives
) ; }
}
package sheet
;
public class WolfAtack extends Decorator { public WolfAtack ( Appearance appearance
) { super ( appearance
) ; } @Override public void display ( ) { super . display ( ) ; appearance
. lives
= appearance
. lives
- 1 ; this . lives
= appearance
. lives
; System
. out
. println ( ) ; System
. out
. println ( "----------------------------------" ) ; System
. out
. println ( "被狼咬了一口,生命值-1,生命值為" + appearance
. lives
) ; System
. out
. println ( "----------------------------------" ) ; System
. out
. println ( ) ; }
}
package sheet
; public class Client { public static void main ( String
[ ] args
) { Sheep sheep
= new Sheep ( "喜羊羊" ) ; sheep
. setlives ( 5 ) ; Appearance redApple
, greenApple
, yellowApple
, wolfAtack
; redApple
= new RedApple ( sheep
) ; wolfAtack
= new WolfAtack ( redApple
) ; wolfAtack
. display ( ) ; greenApple
= new GreenApple ( redApple
) ; wolfAtack
= new WolfAtack ( greenApple
) ; wolfAtack
. display ( ) ; yellowApple
= new YellowApple ( greenApple
) ; yellowApple
. display ( ) ; }
}
結果截圖
三、透明模式和半透明模式的區別
辨析
注意本實例中創建和初始化喜羊羊都是調用setlives()方法
Sheep sheep
= new Sheep ( "喜羊羊" ) ;
sheep
. setlives ( 5 ) ;
而不是
Appearance sheep
= new Sheep ( "喜羊羊" ) ;
sheep
. setlives ( 5 ) ;
是因為Sheep是具體構件類繼承了抽象構件類Appearance的方法,如果需要調用子類Sheep新添加的setLives方法,就要用這種半透明模式定義。
另外方式一中:
Decorator redApple
, greenApple
, yellowApple
; Decorator wolf
= new WolfAtack ( ) ; redApple
= new RedApple ( ) ; redApple
. Decorate ( sheep
) ; wolf
. Decorate ( redApple
) ; wolf
. display ( ) ;
方式二中:
Appearance redApple
, greenApple
, yellowApple
, wolfAtack
; redApple
= new RedApple ( sheep
) ; wolfAtack
= new WolfAtack ( redApple
) ;
方式一是半透明模式,調用了具體裝飾類中新添加的Decorate()方法;而方式二是透明模式,不能直接調用新添加的方法,但是可以一構造方法注入的方式實現。
透明模式
使用抽象構件類型Component定義全部具體構件對象和具體裝飾對象,客戶端可以一致地使用這些對象,因此符合透明裝飾模式的要求。透明裝飾模式可以讓客戶端透明地使用裝飾之前的對象和裝飾之后的對象,無須關心它們的區別,此外,還可以對一個已裝飾過的對象進行多次裝飾,得到更為復雜、功能更為強大的對象。在實現透明裝飾模式時,要求具體裝飾類的operation()方法覆蓋抽象裝飾類的operation()方法,除了調用原有對象的operation()外還需要調用新增的addedBehavior()方法來增加新行為,
半透明模式
透明裝飾模式的設計難度較大,而且有時我們需要單獨調用新增的業務方法。為了能夠調用到新增方法,我們不得不用具體裝飾類型來定義裝飾之后的對象,而具體構件類型還是可以使用抽象構件類型來定義,這種裝飾模式即為半透明裝飾模式,也就是說,對于客戶端而言,具體構件類型無須關心,是透明的;但是具體裝飾類型必須指定,這是不透明的。
思考:為什么半透明裝飾模式不能實現對同一個對象的多次裝飾?
因為在半透明裝飾模式中,使用具體裝飾類來聲明裝飾之后的對象,具體裝飾類中新增的方法并未在抽象構件類中聲明,這樣做的優點在于裝飾后客戶端可以單獨調用在具體裝飾類中新增的業務方法,但是將導致無法調用到之前裝飾時新增的方法,只能調用到最后一次裝飾時具體裝飾類中新增加的方法,故對同一個對象實施多次裝飾沒有任何意義。
四、小結
優缺點
(1) 對于擴展一個對象的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。
(2) 可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的具體裝飾類,從而實現不同的行為。
(3) 可以對一個對象進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合,得到功能更為強大的對象。
(4) 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,原有類庫代碼無須改變,符合“開閉原則”。
(1) 使用裝飾模式進行系統設計時將產生很多小對象,這些對象的區別在于它們之間相互連接的方式有所不同,而不是它們的類或者屬性值有所不同,大量小對象的產生勢必會占用更多的系統資源,在一定程序上影響程序的性能。
(2) 裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味著比繼承更加易于出錯,排錯也很困難,對于多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較為繁瑣。
適用場景
(1) 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
(2) 當不能采用繼承的方式對系統進行擴展或者采用繼承不利于系統擴展和維護時可以使用裝飾模式。不能采用繼承的情況主要有兩類:第一類是系統中存在大量獨立的擴展,為支持每一種擴展或者擴展之間的組合將產生大量的子類,使得子類數目呈爆炸性增長;第二類是因為類已定義為不能被繼承(如Java語言中的final類)。
參考書籍《裝飾模式——Java設計模式劉偉第二版》
總結
以上是生活随笔 為你收集整理的装饰模式——初学JAVA设计模式 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。