Decorator
使用時機:
A.系統需要新增新功能,但不想用繼承造成系統的子類別過多。
B.類別需要「動態」附加新功能。
方法:
1.
定義一個Interface和實作它的Class。
2.
定義一個Abstract Class : Decorator 實作 interface。
3.
定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。
4.
使用裝飾類別~ 宣告並取代原有的物件。
範例:
假設一個遊戲中,主角可以拿槍射擊敵人。
所以我們定義一個槍的interface
: IGun 和 class : CGun ,這是遊戲中最普通的槍。
隨著遊戲升級,武器可以加裝狙擊鏡Scope或是裝填雷射彈藥Laser
ammo。
他們所對應的開火情況便不相同。
1.
定義一個Interface和實作它的Class。
/// <summary>
///
Abstract Class : CGun
/// </summary>
public interface IGun
{
// 槍名
String
GunName { get; set; }
// 開火
void
Fire();
}
/// <summary>
/// CGun實作IGun
/// </summary>
public class CGun : IGun
{
String
sGunName;
//建構子
public
CGun(String _GunName)
{
sGunName = _GunName;
}
// 槍名
public String GunName
{
get
{ return sGunName; }
set
{ sGunName = value; }
}
// 開火
public void Fire()
{
Console.WriteLine(
String.Format("{0}開火! ", sGunName));
}
}
2.
定義一個Abstract Class : Decorator 實作 interface。
/// <summary>
/// 實作IGun 的 Decorator
/// </summary>
public abstract
class Decorator
: IGun
{
public String sGunName;
protected CGun
cGun = null;
//重要:需在此宣告一個protected CGun物件
//透過建構子傳遞被修飾者
public
Decorator( CGun _cGun)
{
this.cGun
= _cGun;
}
// 槍名
public String GunName
{
get
{ return sGunName; }
set
{ sGunName = value; }
}
//委託給被修飾者執行
public virtual void Fire()
{
if
(cGun != null)
{
this.cGun.Fire();
}
}
}
3.
定義其他裝飾類別封裝實體化Decorator類別,並覆寫(override)原有的方法。
(A) 加裝狙擊鏡的裝飾類別
/// <summary>
/// 可以加裝狙擊鏡的 裝飾類別
/// </summary>
public class CScopeDecorator : Decorator //重要:實體化Decorator
{
//建構子 : 繼承基底類別的建構子
public
CScopeDecorator(CGun _cGun)
: base(_cGun)
{
//建構子沒有變化...
}
//重寫父類別的Fire方法
public override void Fire()
{
Console.WriteLine(
String.Format("用裝了狙擊鏡的{0}開火!
", cGun.GunName ));
}
}
(B) 裝填雷射彈藥的裝飾類別
/// <summary>
/// 可以加裝雷射彈藥的 裝飾類別
/// </summary>
public class CLaserDecorator
: Decorator
{
//建構子 : 繼承基底類別的建構子,但是改掉原本的槍名
public
CLaserDecorator(CGun _cGun)
: base(_cGun)
{
//建構子有變化...
_cGun.GunName = "Super Laser Rifle";
}
//重寫父類別的Fire方法
public override void Fire()
{
Console.WriteLine(
String.Format("用裝了雷射彈藥的{0}開火!
", cGun.GunName ));
OverHeat();
}
//新增方法:槍管過熱
private
void OverHeat()
{
Console.WriteLine(
String.Format("警告! {0} 槍管過熱。
", cGun.GunName));
}
}
4.
使用裝飾類別~ 宣告並取代原有的物件。
//宣告一個 CGun物件
IGun myGun = new CGun("Desert Eagle");
myGun.Fire();
//用CScopeDecorator
裝飾原本的
CGun物件
myGun = new CScopeDecorator((CGun)myGun);
myGun.Fire();
//用CLaserDecorator
裝飾原本的
CGun物件
IGun myGun2 = new CLaserDecorator
(
new CGun("???")
);
myGun2.Fire();
顯示結果 :
Desert Eagle開火!
用裝了狙擊鏡的Desert Eagle開火!
用裝了雷射彈藥的Super Laser
Rifle開火!
警告! Super Laser
Rifle 槍管過熱。