Welcome

首页 / 软件开发 / C# / 无废话C#设计模式之十三:Decorator

无废话C#设计模式之十三:Decorator2010-01-13 博客园 lovecherry意图

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

场景

在设计网络游戏的武器系统时,开始并没有考虑到武器的强化和磨损。之后,策划人员说希望给游戏增加强化系统和修理系统,那么我们的武器类型就需要对外提供强化、磨损、修理等方法了。发生这种改动是我们最不愿意看到的,按照设计原则,我们希望功能的扩展尽可能不要修改原来的程序。你可能会想到使用继承来实现,但是策划人员的需求是有的武器能磨损能修理,不能强化,有的武器能强化,但是不会磨损,有的武器既能强化还能磨损和修理。遇到这样的情况,继承的方案可能不适合了,一来继承的层次可能会很多,二来子类的数量可能会很多。

由此,引入装饰模式来解决这个问题。装饰模式使得我们能灵活赋予类额外的职责,并且使得设计和继承相比更合理。

示例代码

using System;

using System.Collections.Generic;

using System.Text;

namespace DecoratorExample

{

class Program

{

static void Main(string[] args)

{

Weapon w = new Rifle();

w.ShowInfo();

Enhance enhancedWeapon = new Enhance(w);

enhancedWeapon.EnhanceAmmo();

enhancedWeapon.ShowInfo();

Wear wornWeapon = new Wear(w);

wornWeapon.WearByRate(0.8);

wornWeapon.ShowInfo();

}

}

abstract class Weapon

{

private double ammo;

public double Ammo

{

get { return ammo; }

set { ammo = value; }

}

private double attack;

public double Attack

{

get { return attack; }

set { attack = value; }

}

private double speed;

public double Speed

{

get { return speed; }

set { speed = value; }

}

private string name;

public string Name

{

get { return name; }

set { name = value; }

}

public abstract void ShowInfo();

}

class Rifle : Weapon

{

public Rifle()

{

this.Ammo = 100;

this.Attack = 10;

this.Speed = 5;

this.Name = "Rifle";

}

public override void ShowInfo()

{

Console.WriteLine(string.Format("ammo {0}", Ammo));

Console.WriteLine(string.Format("attack {0}", Attack));

Console.WriteLine(string.Format("speed {0}", Speed));

Console.WriteLine(string.Format("name {0}", Name));

}

}

abstract class Decorator : Weapon

{

protected Weapon w;

public Decorator(Weapon w)

{

this.w = w;

}

public override void ShowInfo()

{

w.ShowInfo();

}

}

class Enhance : Decorator

{

public Enhance(Weapon w) : base(w) { }

public void EnhanceAmmo()

{

w.Ammo += 20;

Console.WriteLine(">>>>>>>>>>>>Enhanced");

}

}

class Wear : Decorator

{

public Wear(Weapon w) : base(w) { }

public void WearByRate(double rate)

{

w.Speed = w.Speed * rate;

w.Attack = w.Attack * rate;

Console.WriteLine(">>>>>>>>>>>>Worn");

}

}

}