今天繼續設計模式之旅,給大家帶來裝飾者模式,國際慣例,先看定義。
裝飾者模式:若要擴充套件功能,裝飾者提供了比整合更有彈性的替代方案,動態地將責任附加到物件上。
先簡單描述下裝飾者模式發揮作用的地方,當我們設計好了一個類,我們需要給這個類新增一些輔助的功能,並且不希望改變這個類的程式碼,這時候就是裝飾者模式大展雄威的時候了。這裡還體現了一個原則:類應該對擴充套件開放,對修改關閉。
下面進入正題,今天在那看電影,忽然想起年輕時在遊戲場上的血雨腥風啊,哈哈,下面以遊戲為背景介紹裝飾者模式。玩過遊戲的兄弟應該都知道,遊戲裡面每個角色有武器、鞋子、護腕、戒指、還有各種紅寶石、藍寶石、黃寶石等等。
下面需求開始:設計遊戲的裝備系統,基本要求,要可以計算出每種裝備在鑲嵌了各種寶石後的攻擊力和描述:
具體需求:
1、武器(攻擊力20) 、戒指(攻擊力5)、護腕(攻擊力5)、鞋子(攻擊力5)
2、藍寶石(攻擊力5/顆)、黃寶石(攻擊力10/顆)、紅寶石(攻擊力15/顆)
3、每個裝備可以隨意鑲嵌3顆
好了,需求介紹完畢,當然了,不要吐槽我的設計,尼瑪鞋子哪來的攻擊力,關鍵時刻也是可以砸人的嘛。下面開始初步的設想,出於多年物件導向的經驗,我們可能會這麼設計:
如果你這麼設計了,我靠,就這麼點需求你寫了幾百個類,隨便新增兩個寶石,哈哈,指數增長聽過麼,準備加班吧。
可能你還會這麼設計:寫一個超類,然後裡面各種set寶石,然後在計算攻擊力的地方,使勁的If有哪幾種寶石,恭喜你,程式碼量不是很大,但是隨便新增個武器,你得又多寫多少個IF呢。
上面敘述了一些可能性的設計,都不是很好,下面看看如何將裝飾者模式融入:
首先是裝備的超類
package com.zhy.pattern.decorator;
/**
* 裝備的介面
*
* @author zhy
*
*/
public interface IEquip
{
/**
* 計算攻擊力
*
* @return
*/
public int caculateAttack();
/**
* 裝備的描述
*
* @return
*/
public String description();
}
然後分別是武器、戒指、護腕、鞋子
package com.zhy.pattern.decorator;
/**
* 武器
* 攻擊力20
* @author zhy
*
*/
public class ArmEquip implements IEquip
{
@Override
public int caculateAttack()
{
return 20;
}
@Override
public String description()
{
return "屠龍刀";
}
}
package com.zhy.pattern.decorator;
/**
* 戒指
* 攻擊力 5
* @author zhy
*
*/
public class RingEquip implements IEquip
{
@Override
public int caculateAttack()
{
return 5;
}
@Override
public String description()
{
return "聖戰戒指";
}
}
package com.zhy.pattern.decorator;
/**
* 護腕
* 攻擊力 5
* @author zhy
*
*/
public class WristEquip implements IEquip
{
@Override
public int caculateAttack()
{
return 5;
}
@Override
public String description()
{
return "聖戰護腕";
}
}
package com.zhy.pattern.decorator;
/**
* 鞋子
* 攻擊力 5
* @author zhy
*
*/
public class ShoeEquip implements IEquip
{
@Override
public int caculateAttack()
{
return 5;
}
@Override
public String description()
{
return "聖戰靴子";
}
}
接下來當然是裝飾品,寶石了,首先超類
package com.zhy.pattern.decorator;
/**
* 裝飾品的介面
* @author zhy
*
*/
public interface IEquipDecorator extends IEquip
{
}
下來藍寶石、黃寶石、紅寶石
package com.zhy.pattern.decorator;
/**
* 藍寶石裝飾品
* 每顆攻擊力+5
* @author zhy
*
*/
public class BlueGemDecorator implements IEquipDecorator
{
/**
* 每個裝飾品維護一個裝備
*/
private IEquip equip;
public BlueGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 5 + equip.caculateAttack();
}
@Override
public String description()
{
return equip.description() + "+ 藍寶石";
}
}
package com.zhy.pattern.decorator;
/**
* 黃寶石裝飾品
* 每顆攻擊力+10
* @author zhy
*
*/
public class YellowGemDecorator implements IEquipDecorator
{
/**
* 每個裝飾品維護一個裝備
*/
private IEquip equip;
public YellowGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 10 + equip.caculateAttack();
}
@Override
public String description()
{
return equip.description() + "+ 黃寶石";
}
}
package com.zhy.pattern.decorator;
/**
* 紅寶石裝飾品 每顆攻擊力+15
*
* @author zhy
*
*/
public class RedGemDecorator implements IEquipDecorator
{
/**
* 每個裝飾品維護一個裝備
*/
private IEquip equip;
public RedGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 15 + equip.caculateAttack();
}
@Override
public String description()
{
return equip.description() + "+ 紅寶石";
}
}
好了,到此結束,我們已經實現了需求的功能了,是不是每個類都很清晰加簡單,下面看測試:
package com.zhy.pattern.decorator;
public class Test
{
public static void main(String[] args)
{
// 一個鑲嵌2顆紅寶石,1顆藍寶石的靴子
System.out.println(" 一個鑲嵌2顆紅寶石,1顆藍寶石的靴子");
IEquip equip = new RedGemDecorator(new RedGemDecorator(new BlueGemDecorator(new ShoeEquip())));
System.out.println("攻擊力 : " + equip.caculateAttack());
System.out.println("描述 :" + equip.description());
System.out.println("-------");
// 一個鑲嵌1顆紅寶石,1顆藍寶石的武器
System.out.println(" 一個鑲嵌1顆紅寶石,1顆藍寶石,1顆黃寶石的武器");
equip = new RedGemDecorator(new BlueGemDecorator(new YellowGemDecorator(new ArmEquip())));
System.out.println("攻擊力 : " + equip.caculateAttack());
System.out.println("描述 :" + equip.description());
System.out.println("-------");
}
}
輸出:
一個鑲嵌2顆紅寶石,1顆藍寶石的靴子
攻擊力 : 40
描述 :聖戰靴子+ 藍寶石+ 紅寶石+ 紅寶石
一個鑲嵌1顆紅寶石,1顆藍寶石,1顆黃寶石的武器
攻擊力 : 50
描述 :屠龍刀+ 黃寶石+ 藍寶石+ 紅寶石
贊不讚,要是需求隨便多幾個裝備,幾種寶石,我們隨隨便便就可以加上,然後開開心心下班。
好了,恭喜你,你又學會了一個設計模式,裝飾者模式。
現在根據例子對定義的理解,不用我多說吧。
Java的API中也有裝飾者模式的身影,如果你初學Java,一定記得Java裡面的各種流,很痛苦吧,但是當你明
白你們的設計之後就會感覺清晰很多。
把InputStream看作我們的IEquip,把FilterInputStream看作我們的IEquipDecorator,是不是和我們的設計幾乎一樣~