简介
装饰器(又称修饰器)模式是设计模式之一,它能在不改变原有类的情况下扩展已有类的功能。
在游戏开发中,装饰器模式适用于装扮或者功能性道具的交互,这样角色类本身就不需要包含对应逻辑。
例子
简单地,装饰类可以写成一个组合目标对象,但不包含目标本身原有数据的类。
例如有一个角色类Character,拥有血量(HP)属性,可以实现移动(Move),进食(Eat)等基础功能。现在想添加两种药水道具,使角色吃下去后分别可以飞行、游泳。
那么可以编写修饰类Decorator,其大致结构如下:
public class Decorator:Character
{
protected Character player;
public new int HP { get { return player.HP; } }
public new void Move() { player.Move(); }
public new void Eat() { player.Eat(); }
}
然后,编写具体的修饰器FlyDecorator和SwimDecorator
public class FlyDecorator:Decorator
{
public FlyDecorator(Character _player)
{
player = _player;
}
public void Fly() { Debug.Log("Fly"); }
}
public class SwimDecorator:Decorator
{
public SwimDecorator(Character _player)
{
player = _player;
}
public void Swim() { Debug.Log("Swim"); }
}
新建一个Character,测试一下
Character Acoloco = new Character();
FlyDecorator FlyAcoloco = new FlyDecorator(Acoloco);
SwimDecorator SwimAcoloco = new SwimDecorator(FlyAcoloco);
Acoloco.Move();
FlyAcoloco.Fly();
SwimAcoloco.Swim();
可以看到,使用装饰器模式扩展了原有Character类的功能。这在不方便修改原类的时候尤为有效,例如当你使用了某些框架时,你可以结合具体业务需求编写修饰类,扩展类功能从而简化工作。
更多
为什么修饰类要继承原有基类,不继承会怎么样?
Decorator类不继承Character类的情况
public class Decorator //不再继承Character
{
protected Character player;
//不需要再使用new隐藏
public int HP { get { return player.HP; } }
public void Move() { player.Move(); }
public void Eat() { player.Eat(); }
}
FlyCharacter和SwimCharacter部分保持不变
在取消继承基类的情况下,上面的程序仍可正常运行,但是此时有以下缺点:
- Decorator与Character类型不兼容。失去继承关系后,任何需要填入Character类型参数的地方,都不能使用Decorator替代,极大地限制了Decorator的使用范围。
- 由于第一点,被修饰过实例的二次修饰受到限制。例如原先A,B,C三个修饰类可以互相修饰,但在失去共同基类后,只能采用B修饰A,C修饰B这样的顺序修饰(除非你愿意把所有修饰情况全写进去)。
为什么不直接使用继承(使用子类),而是使用组合(使用装饰器)?
使用直接继承的修饰类其实就是在使用子类
public class Decorator:Character
{
}
public class FlyDecorator:Decorator
{
public void Fly() { Debug.Log("Fly"); }
}
- 装饰器模式使用组合而非继承,减少了可能存在的子类的数量。例如某个角色类有6种形态和7套装扮(假设形态和装扮系统只在某个特殊游戏模式中生效,那将其直接组合至角色类中显然是不合适的,因此需要使用装饰器)。直接使用继承的话需要编写6*7=42个类,而使用组合只需要编写6+7=13个类,显然是使用组合更加高效。
- 使用组合可以动态增减功能。例如对于Character类型的实例Acoloco,当要增加飞行功能时可以直接new FlyCharacter(Acoloco)得到会飞的FlyCharacter类型实例,而要减少功能时可以直接停止使用FlyCharacter类,继续使用Character类。若使用继承,则需要将实例在不同的类型间转换,并在每次转换类型的同时都要完成数据的拷贝。
- 使用组合能减少数据存储,利于维护。FlyCharacter类型本身只引用Character中的数据类型,而不储存。而使用继承(使用子类)就需要先利用Character类中数据对FlyCharacter类型数据进行初始化,此时同时存在多份数据,不易管理。
© 版权声明
文章版权归作者所有
THE END





- 最新
- 最热
只看作者