【发布时间】:2010-08-27 22:38:29
【问题描述】:
我正在努力解决一个设计问题,我不希望我的代码因为一个糟糕的解决方案而变得一团糟。我将仅解释我的确切情况,而不是给出一个糟糕的类比。
我正在尝试编写 Wii Play Tanks 的克隆,但在设计 Tank 类时遇到了问题。 Tank 本身是唯一这样的类,它对其部分使用依赖注入。现在的两个部分是TankAI 和TankWeapon。 AI 处理关于移动和射击的决定,武器描述武器的行为 - 它发射什么弹丸,以及发射频率等。我有一个工厂类,可以制造不同组合的坦克。
我的射弹类是在一个抽象的Projectile 类下设置的。每个子类都描述了弹丸的型号、弹跳次数、速度等。
我遇到的问题是每个TankWeapon 子类都在它们构造新射弹的区域周围复制大量代码,因为它们每个都构造不同的类。我想将此代码移动到基类中,但我必须以某种方式注入武器需要构建的射弹类本身。我知道我可以在构造时将一个类直接传递给基础,但这感觉是错误的方式。
当我们这样做的时候,我遇到了另一个设计问题:我怎样才能让我的 AI 类也知道射弹类?他们的决定将取决于发射的弹丸的属性,例如它们可以从墙上反弹多少次。在注入时,AI 和 Weapon 类都被赋予了对父 Tank 的引用。
编辑:
看来我最初的问题有点令人困惑,所以我将发布代码。我已经为我的坦克设置了 DI。
public class Tank : ISolidObject
{
public TankAI AISystem { get; private set; }
public TankWeapon Weapon { get; private set; }
public Tank(TankAI aiSystem, TankWeapon weapon)
{
this.AISystem = aiSystem;
this.AISystem.Tank = this;
this.Weapon = weapon;
this.Weapon.Tank = this;
}
}
public abstract class TankAI
{
public Tank Tank { get; set; }
public abstract void Think();
}
// TankAI implementations aren't important here
public abstract class TankWeapon
{
protected int maxShotsOnScreen, shotsOnScreen;
public Tank Tank { get; set; }
public virtual void Shoot()
{
shotsOnScreen++;
// I really want to put the projectile construction code in here
}
}
public class BulletWeapon : TankWeapon
{
public BulletWeapon()
{
this.maxShotsOnScreen = 5;
this.turnSpeed = 1;
}
public override void Shoot()
{
// here's my problem. Every weapon class duplicates this, because I can't put the projectile construction in the base weapon class.
if (shotsOnScreen >= maxShotsOnScreen) return;
base.Shoot();
// just create it, it will take care of the rest
double bx = Tank.X - Math.Sin(Tank.AngleTurret * Math.PI / 180.0);
double by = Tank.Y + Math.Cos(Tank.AngleTurret * Math.PI / 180.0);
// note that projectiles subscribe themselves to the game entity handler, so don't have to store it myself.
// this weapon creates bullets. A different weapon might create rockets. How would the base class know which? Is there any way I can prevent this code from being duplicated?
new Bullet(bx, by, Tank.AngleTurret).Death += ShotDeath;
}
private void ShotDeath(Projectile p)
{
p.Death -= ShotDeath;
shotsOnScreen--;
}
}
【问题讨论】:
标签: c# design-patterns dependency-injection class-design