装饰者模式,主要是为了解决在对类进行扩展过程中可能出现的子类爆炸,并同时满足“对扩展开放,对修改封闭”的原则。我们以游戏中的武器作为例,游戏中的武器有基本的伤害值,有附加的特效,特效的种类比较多,且同一个武器会带有多种特效,例如伤害增强10%,攻击速度增强20%等等,若采用继承的方式来做,就会产生子类爆炸,同时,如果需要增加一种新的特效的话,就需要修改原来的代码。但是如果采用装饰者模式,就可以比较简单的解决这个问题,在用代码实现之前,我们先画一下模式图。
装饰者模式中分为这么几种角色,一个是抽象组件,对应途中是weapon类,一个是具体组件,对应各类武器,例如sword类,另一个是抽象装饰类,抽象装饰类也继承于抽象组件,是为了装饰者中有一个实例变量以保存对weapon的引用,最后是具体装饰类,负责添加具体的特性。具体的实现代码如下:
抽象组件:
public abstract class Weapon
{
public abstract void GetDescription();
}
具体组件:
public class Sword:Weapon
{
public override void GetDescription()
{
Console.WriteLine("This is a Sword");
}
}
抽象装饰类:
public abstract class effect:Weapon
{
private Weapon _weapon;
public effect(Weapon weapon)
{
_weapon = weapon;
}
public override void GetDescription()
{
if(_weapon != null)
{
_weapon.GetDescription();
}
}
}
具体装饰类(增强10%伤害):
public class EnhanceAttack : effect
{
public EnhanceAttack(Weapon weapon):base(weapon)
{
}
public override void GetDescription()
{
base.GetDescription();
Console.WriteLine("Add 10% Attack");
}
}
具体装饰类(增加10%速度):
public class IncreaseSpeed : effect
{
public IncreaseSpeed(Weapon weapon):base(weapon)
{
}
public override void GetDescription()
{
base.GetDescription();
Console.WriteLine("Increase 10% Speed!");
}
}
具体使用:
static void Main(string[] args)
{
// 新建一个Sword对象
Weapon weapon = new Sword();
// 对Sword对象添加伤害增强特效
weapon = new EnhanceAttack(weapon);
// 对Sword对象再添加增加攻击速度特效
weapon = new IncreaseSpeed(weapon);
weapon.GetDescription();
Console.WriteLine("-----------------------");
Console.ReadLine();
}
结果:
如果后期需要增加新的特效,例如按4%伤害吸取生命,则可以再新建一个具体装饰类,而无需更改原先的代码。
在上面这个例子中,假设让具体装饰类直接继承抽象组件类,将对weapon的引用直接放到具体装饰类中,不需要抽象装饰类也能实现一样的目的,如代码所示:
public class IncreaseSpeed : Weapon
{
private Weapon _weapon;
public IncreaseSpeed(Weapon weapon)
{
_weapon = weapon;
}
public override void GetDescription()
{
_weapon.GetDescription();
Console.WriteLine("Increase 10% Speed!");
}
}
在逻辑不复杂的情况下,用这种方式也能实现一样的功能,但是当功能比较复杂的时候,比如需要按照步骤执行一些操作的时候,则需要将这些步骤放到抽象装饰类,然后在具体装饰类中再根据实际需求装饰每个步骤。