導讀
這篇文章中我不會使用概念性文字來說明裝飾者模式。由於通常概念性的問題都非常抽象。非常難懂。使得讀者非常難明確究竟為什么要使用這樣的設計模式。我們設計模式的誕生,肯定是前輩們在設計程序的時候遇到了某種困難,為了避免這樣的苦難的發生,從而設計出來的這樣的設計模式,所以這篇文章中我會帶領大家遇見這樣的困難,從而使用設計模式解決這樣的困難,最后大家就會明確什么是設計者模式,什么時候應該使用設計者模式以及怎樣使用設計者模式了
首先我們先來看一下裝飾者模式的UML圖是什么樣子的。圖中各個類的含義不懂沒有關系,以下我會用一個形象的樣例來一一介紹他們,相信大家看完后肯定就明確了
假設不用裝飾者設計模式會出現什么問題?
這里我不准備用一些概念性的文字來說明什么是裝飾者模式,我就要用一個實際的樣例來形象的說明什么是裝飾者模式。
比方我們玩網絡游戲。我們都要先創建一個角色對吧,這些角色每一個人創建出來的都不一樣,由於角色肯定能夠依據用戶的審美來個性化打造,但是每一個角色最開始的能力都是一樣的,不會由於一個玩家給他捏了一張特別帥的臉而變得特別的厲害。
那么這個角色肯定是一個接口,這就是UML圖中的Conponent接口
/** * 游戲角色 */
public interface Avatar {
String describe();
}
非常easy,僅僅有一個方法,我們僅僅用來演示。真正的游戲角色不可能僅僅有這么簡單。describe方法用來描寫敘述這個角色。
好,我們玩游戲肯定有職業對吧,假設我們這款游戲僅僅設計了4種職業:戰士(Worrior),法師(Mage),獵人(Hunter),術士(Warlock)。我們要創建4個實現類。這就相應ConcreteComponent類
public class Worrior implements Avatar {
@Override
public String describe() {
return "戰士";
}
}
public class Mage implements Avatar {
@Override
public String describe() {
return "法師";
}
}
public class Hunter implements Avatar {
@Override
public String describe() {
return "獵人";
}
}
public class WarLock implements Avatar {
@Override
public String describe() {
return "術士";
}
}
好了,如今我們已經創建好4種職業的游戲角色了。如今我們的玩家認為太單調了,全部相同職業的角色都長一個樣子,你們應該同意我們在創建角色的時候能夠改動角色的外觀。比方選擇頭發顏色。
這可怎么辦,我們有4種職業啊,每種職業提供3種顏色的頭發。我們得再創建12個子類啊,並且之前設計的4個實現類的作用也就不大了,由於大家肯定都去改變一下頭發的顏色。
好。先硬着頭皮來寫吧。
public class WorriorWithRedHair implements Avatar{
@Override
public String describe() {
return "戰士+紅顏色頭發";
}
}
public class WorriorWithGreenHair implements Avatar{
@Override
public String describe() {
return "戰士+綠顏色頭發";
}
}
public class WorriorWithBlueHair implements Avatar{
@Override
public String describe() {
return "戰士+藍顏色頭發";
}
}
public class MageWithRedHair implements Avatar{
@Override
public String describe() {
return "法師+紅顏色頭發";
}
}
public class MageWithGreenHair implements Avatar{
@Override
public String describe() {
return "法師+綠顏色頭發";
}
}
public class MageWithBlueHair implements Avatar{
@Override
public String describe() {
return "法師+藍顏色頭發";
}
public class HunterWithRedHair implements Avatar{
@Override
public String describe() {
return "獵人+紅顏色頭發";
}
}
public class HunterWithGreenHair implements Avatar{
@Override
public String describe() {
return "獵人+綠顏色頭發";
}
}
public class HunterWithBlueHair implements Avatar{
@Override
public String describe() {
return "獵人+藍顏色頭發";
}
public class WarLockWithRedHair implements Avatar{
@Override
public String describe() {
return "術士+紅顏色頭發";
}
}
public class WarLockWithGreenHair implements Avatar{
@Override
public String describe() {
return "術士+綠顏色頭發";
}
}
public class WarLockWithBlueHair implements Avatar{
@Override
public String describe() {
return "術士+藍顏色頭發";
}
好了。加班到半夜,最終寫完了。第二天上班,老板來找你了,如今我們的玩家越來越多了,他們反映說我們的角色還是太單調。我們還要讓玩家能夠選擇上衣的顏色和褲子的顏色,上衣有5種顏色,褲子有5種顏色。
聽完這個需求,我想你也應該吐血了。
比方玩家A會選擇戰士+紅色頭發+白色上衣+藍色褲子,玩家B會選擇術士+藍色頭發+白色上衣+黃色褲子。
這組合也太多了。這得寫多少個實現類。
這樣的方法肯定是行不通的。
使用裝飾者模式怎樣解決這個問題?
這時公司來了個大牛。他聽說了這個情況,接下了這個需求,你心想他一定是瘋了。但是第二天他就完畢了任務。你吃了一大驚,趕緊去看他的代碼是怎么實現的。原來這位大牛使用了你連聽都沒說過的裝飾者設計模式。
首先他設計了一個類。實現了Avatar接口,並且傳入了一個Avatar對象,這就相應UML圖中的Decorator
public class AvatarDecorator implements Avatar {
private Avatar av;
public AvatarDecorator(Avatar avatar){
av = avatar;
}
@Override
public String describe() {
return av.describe();
}
}
我們看到他里面持有一個Avatar類型的對象,在describe方法中實際調用的也是av的describe對象,我們傳入的Avatar對象也就是我們須要進行裝飾的對象了。
好。如今我們先來設計頭發顏色的裝飾類
public class RedHair extends AvatarDecorator {
public RedHair(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+紅色頭發";
}
}
public class GreenHair extends AvatarDecorator {
public GreenHair(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+綠色頭發";
}
}
public class BlueHair extends AvatarDecorator {
public BlueHair(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+藍色頭發";
}
}
我們看到。我們的構造方法是調用的super()的構造方法,也就是調用的AvatarDecorator的構造方法,我們的describe中也先調用了super.describe()然后后面加上了我們的裝飾內容,也就是說我們傳進來的一個Avatar對象被我們裝飾了。
這就相當於UML中的ConcreteDecorator。
好了,如今玩家想要創建一個角色的話就能夠這樣創建出來
//紅色頭發戰士
Avatar avatar1 = new RedHair(new Worrior());
//綠色頭發術士
Avatar avatar2 = new GreenHair(new WarLock());
接下來我們再設計上衣和褲子的裝飾類
public class WhiteJacket extends AvatarDecorator {
public WhiteJacket(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+白色上衣";
}
}
public class RedJacket extends AvatarDecorator {
public RedJacket(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+紅色上衣";
}
}public class BlackJacket extends AvatarDecorator {
public BlackJacket(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+黑色上衣";
}
}public class GreenJacket extends AvatarDecorator {
public GreenJacket(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+綠色上衣";
}
}public class BlueJacket extends AvatarDecorator {
public BlueJacket(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+藍色上衣";
}
}
public class WhitePants extends AvatarDecorator {
public WhitePants(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+白色褲子";
}
}
public class BlackPants extends AvatarDecorator {
public BlackPants(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+黑色褲子";
}
}
public class RedPants extends AvatarDecorator {
public RedPants(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+紅色褲子";
}
}
public class GreenPants extends AvatarDecorator {
public GreenPants(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+綠色褲子";
}
}
public class BluePants extends AvatarDecorator {
public BluePants(Avatar avatar) {
super(avatar);
}
@Override
public String describe() {
return super.describe()+"+藍色褲子";
}
}
好了。如今我們就能夠隨意組合我們的角色了
//綠色頭發獵人穿着白色上衣和黑色褲子
Avatar avatar3 = new GreenHair(new WhiteJacket(new BlackPants(new Hunter())));
//紅色頭發法師穿着紅色上衣和白色褲子
Avatar avatar4 = new RedHair(new RedJacket(new WhitePants(new Mage())));