1、子類復子類,子類何其多
1)假如咱們須要爲遊戲中開發一種坦克,除了各類不一樣型號的坦克外,咱們還但願在不一樣場合中爲其增長如下一種或多種功能:好比紅外線夜視功能,好比水陸兩棲功能,好比衛星定位功能等等。
2)這是遊戲的設計坦克,所以這個定位要定位在軟件的組件的設計。設計模式
//坦克抽象類
public abstract class Tank
{
public abstract void Shot();
public abstract void Run();
}
//各類型號
public class T50 : Tank
{
//.....
}
public class T75 : Tank
{
//.....
}
public class T90 : Tank
{
//.....
}
//各類不一樣功能的組合
public class T50A : T50, IA
{
//......
}
public class T50B : T50, IB
{
//......
}
public class T50C : T50, IC
{
//......
}
public class T50AB : T50, IA, IB
{
//......
}
public class T50BC : T50, IB, IC
{
//......
}
public class T50ABC : T50, IA, IB, IC
{
//......
}
......
3)分析:隨着功能的擴展(各類功能的排列組合),子類會急劇膨脹。一個微小的變更就帶來了很大的震動,
這時候咱們引入了裝飾(Decorator)模式解決這類問題。
2、動機(Motivation)
1)上述描述的問題根源在於咱們「過分地使用了繼承來擴展對象的功能」,因爲繼承爲類型引入的靜態特質,使得這種擴展方式缺少靈活性;而且隨着子類的增多(擴展功能的增多),各類子類的組合(擴展功能的組合)會致使更多子類的膨脹(多繼承)。
2)如何使「對象功能的擴展」可以根據須要來動態地實現?同時避免「擴展功能的增多」帶來的子類膨脹問題?從而使得任何「功能擴展變化」所致使 的影響將爲最低?
3、意圖(Intent)
動態地給一個對象增長一些額外的職責(功能)。就增長功能而言,Decorator模式比生成子類更爲靈活。
——《設計模式》GoF
4、實例:擴展坦克在不一樣場合下的功能
1)下面用類繼承的解決辦法,擴展多種功,會致使子類過多
//坦克的抽象類
public abstract class Tank
{
//各類功能
public abstract void Shot();
public abstract void Run();
}網絡
//各類型號的坦克
public class T50 : Tank
{
public override void Shot()
{
}
public override void Run()
{
}
}ide
public class T75 : Tank
{
public override void Shot()
{
}
public override void Run()
{
}
}this
public class T90 : Tank
{
public override void Shot()
{
}
public override void Run()
{
}
}加密
//擴展功能的接口
public interface IA
{
//擴展功能
void ShotA();
void RunA();
}設計
public class T50 : Tank, IA
{
private void IA.ShotA()
{
}
private void IA.RunA()
{
}
public override void Shot()
{
this.ShotA(); //功能擴展
//do shot...
base.Shot();
}
public override void Run()
{
this.RunA();//功能擴展
//do run...
base.Run();
}
}對象
2)應用Decorator模式設計功能擴展
//坦克的抽象類
public abstract class Tank
{
//各類功能
public abstract void Shot();
public abstract void Run();
}繼承
//T50型號的坦克
public class T50 : Tank
{
public override void Shot()
{
}
public override void Run()
{
}
}接口
//擴展功能
public abstract class Decorator : Tank //實際是接口繼承
{
private Tank _tank; //Has-A 對象組合
public Decorator(Tank tank)
{
this._tank = tank;
}
public override void Shot()
{
_tank.Shot();
}
public override void Run()
{
_tank.Run();
}
}遊戲
public class DecoratorA : Decorator
{
//構造器是不繼承的,要進行相應設置
public DecoratorA(Tank tank) : base(tank)
{
}
public override void Shot()
{
//紅外功能擴展
//do shot...
base.Shot();
}
public override void Run()
{
//紅外功能擴展
//do run...
base.Run();
}
}
public class DecoratorB : Decorator
{
//構造器是不繼承的,要進行相應設置
public DecoratorB(Tank tank) : base(tank)
{
}
public override void Shot()
{
//水陸兩棲功能擴展
//do shot...
base.Shot();
}
public override void Run()
{
//水陸兩棲功能擴展
//do run...
base.Run();
}
}
public class DecoratorC : Decorator
{
//構造器是不繼承的,要進行相應設置
public DecoratorC(Tank tank) : base(tank)
{
}
public override void Shot()
{
//衛星定位功能擴展
//do shot...
base.Shot();
}
public override void Run()
{
//衛星定位功能擴展
//do run...
base.Run();
}
}
//客戶程序
class App
{
public static void Main()
{
Tank tank = new T50();
DecoratorA da = new DecoratorA(tank);//紅外
DecoratorB db = new DecoratorB(da);//紅外,兩棲
DecoratorC dc = new DecoratorB(db);//紅外,兩棲,衛星定位
}
}
5、Decorator模式的幾個要點 1)經過採用組合、而非繼承的手法,Decorator模式實現了在運行時動態地擴展對象功能的能力,並且能夠根據須要擴展多個功能。避免了單獨使用繼承帶來的「靈活性差」和「多子類衍生問題」。 2)Component類在Decorator模式中充當抽象接口的角色,不該該去實現具體的行爲。並且Decorator類對於Component類應該透明——換言之Component類無需知道Decorator類,Decorator類是從外部來擴展Component類的功能。 3)Decorator類在接口上表現爲is-a Component的繼承關係,即Decorator類繼承了Component類所具備的接口。但在實現上又表現爲has-a Component的組合關係,即Decorator類又使用了另一個Component類。咱們可使用一個 或者多個Decorator對象來「裝飾」一個Component對象,且裝飾後的對象仍然是一個Component對象。 4)Decorator模式並不是解決「多子類衍生的多繼承問題」,Decorator模式應用的要點在於解決「主體類在多個方向上的擴展功能」——是爲「裝飾」的含義。 6、.NET框加中的Decorator應用 抽象接口: Stream(流) 實體類:繼承Stream FileStream(文件流) NetworkStream(網絡流) MemoryStrem(內存流) 裝飾對象:繼承Stream,內部還包括一個Stream字段 BufferedStream(緩衝功能擴展) CryptoStream(加密功能擴展)