我们先理解下什么情况会用到Decorator装饰模式。
比如我们设计一个游戏人物,人物拥有的装扮,如衣服,裤子,靴子,手套,戒指,帽子 等 这些类型的开发,又或者是设计一个部件,比如一个武器凹槽,我们这个武器凹槽可以加 激光炮,加农炮,枪,防御盾。再或者我们制作游戏人物的技能框,里面可以有各种各样的技能。
这些时候只要是在同一个部件下,这个部件可以拥有很多独立而且等级平行的单位对象时,我们就可以采用Decorator装饰模式来进行开发。首先来看看Decorator装饰模式的原理实现,上代码。
abstract class Component
{
public abstract void Operation();
}
class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("具体对象的操作");
}
}
abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)
{
this.component = component;
}
public override void Operation()
{
component.Operation();
}
}
class ConcreteDecoratorA : Decorator
{
private string addedState;
public override void Operation()
{
base.Operation();
addedState = "New State";
Console.WriteLine("具体装饰对象A的操作");
}
}
class concreteDecoratorB : Decorator
{
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("具体装饰对象B的操作");
}
private void AddedBehavior()
{
}
}
代码里先定义了一个Component的抽象父类,有一个Operation方法。然后定义一个操作对象的子类 ConcreteComponent 。来执行具体的操作逻辑。 这时候我们就可以定义一个装饰类Decorator 了,装饰类继承Component 。再多了一个SetComponent方法,用来把外部传输进来的其他装饰类保存下来,而且自身的执行方法Operation也是调用被传进来的类方法。 最后,我们就声明两个实体的装饰类AConcreteDecoratorA 和ConcreteDecoratorB ,都继承Decorator 装饰类。 装饰类A有一个独有的 string 字段。 装饰类B有一个独有的AddedBehavior()方法,这两个用来区分下它们两个的不同之处。然后我们来调用一下,并且看看运行效果。
public static void Mains()
{
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
concreteDecoratorB d2 = new concreteDecoratorB();
d1.SetComponent(c);
d2.SetComponent(d1);
d2.Operation();
Console.ReadKey();
}
static void Main(string[] args)
{
//Base.Mains(); //装饰模式 基础知识的调用 全部代码都在Base的类里面 取消注释就可以运行了
SkillBar skill1 = new SkillBar("恶魔猎手");
ManaBurn mb = new ManaBurn();
Immolation ii = new Immolation();
Evasion ev = new Evasion();
Metamorphosis me = new Metamorphosis();
mb.Decorate(skill1);
ii.Decorate(mb);
ev.Decorate(ii);
me.Decorate(ev);
me.Show();
Console.WriteLine();
SkillBar skill2 = new SkillBar("剑圣");
WindWalk ww = new WindWalk();
MirrorImage mi = new MirrorImage();
CriticalStrike cs = new CriticalStrike();
Bladestorm bl = new Bladestorm();
ww.Decorate(skill2);
mi.Decorate(ww);
cs.Decorate(mi);
bl.Decorate(cs);
bl.Show();
Console.ReadKey();
}
}
class SkillBar
{
public SkillBar()
{
}
private string name;
public SkillBar(string name)
{
this.name = name;
}
public virtual void Show()
{
Console.WriteLine("--------------------{0}的技能条---------------------", name);
}
}
//技能操作类
class Skills : SkillBar
{
protected SkillBar component;
public void Decorate(SkillBar component)
{
this.component = component;
}
public override void Show()
{
if (component != null)
{
component.Show();
}
}
}
//技能装饰类
class ManaBurn : Skills
{
public override void Show()
{
Console.WriteLine("(魔法燃烧):使敌人的魔法值成为同点伤害数(耗魔法75)");
base.Show();
}
}
class Immolation : Skills
{
public override void Show()
{
Console.WriteLine("(献祭):造成周围伤害(耗魔法35");
base.Show();
}
}
class Evasion : Skills
{
public override void Show()
{
Console.WriteLine("(闪避):英雄周围的我方士兵回避率增高(不需要使用即一直保持)");
base.Show();
}
}
class Metamorphosis : Skills
{
public override void Show()
{
Console.WriteLine("(变身)把自己变成强力恶魔,远程攻击,体力加500,持续60秒(耗魔法150)。");
base.Show();
}
}
class WindWalk : Skills
{
public override void Show()
{
Console.WriteLine("(风速行走):英雄隐身且快速移动");
base.Show();
}
}
class MirrorImage : Skills
{
public override void Show()
{
Console.WriteLine("(镜像):召影子一起战斗,时间持续60秒。(耗魔法150)");
base.Show();
}
}
class CriticalStrike : Skills
{
public override void Show()
{
Console.WriteLine("(强力伤害):周围部队造成更多伤害");
base.Show();
}
}
class Bladestorm : Skills
{
public override void Show()
{
Console.WriteLine("(大刀乱舞):乱砍周围地面敌人,每秒110伤害值");
base.Show();
}
}
调用一我们先声明了一个技能条类
SkillBar ,
里面有一个Show方法。 然后声明一个技能操作类
Skills.继承SkillBar。里面有一个装饰方法Decorate和重写父类Show方法,
然后下面就是各个不同的技能类。都继承于技能操作类。 重写Show方法,处理自己的逻辑,然后调用父类Show方法。最后我们在Main方法 声明两个技能条名称( 恶魔猎手和剑圣)
然后分别把属于他们各自的技能声明好,然后就像叠罗汉一个把他们拼接起来。
可以看到,输出的效果就是我们按照的装饰顺序输出的。看完这里是不是觉得Decorator装饰模式特别简单却又特别好用呢,OK,我们再来回顾下Decorator装饰模式的一些要点和注意事项。
通过采用组合,而非继承的手法,Decorator装饰模式实现了在运动时动态地扩展对象功能的能力,而且可以根据需求扩展多个功能,避免了单独使用继承带来的"灵活性差"和"多子类衍生问题"。
Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为,而且Decorator类对于Component类应该透明--换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的借口,但在实现上又表现为 has-a component的组合关系,即Decorator类又使用了另外一个Component类,我们可以使用一个或者多个Decorator对象来装饰一个component对象,且装饰后的对象仍然是一个component对象。
Decorator装饰模式并非解决"多子类衍生的多继承"问题,Decorator装饰模式应用的要点在于解决"主体类在多个方向上的扩展功能"--是为装饰的含义。
总的来说,Decorator装饰模式可以动态的给一个对象增加一些额外的职责,就增加功能而言,Decorator装饰模式比生产子类更为灵活。