代码之家  ›  专栏  ›  技术社区  ›  Tesserex

如何依赖注入类/类型?

  •  3
  • Tesserex  · 技术社区  · 14 年前

    我正在努力解决一个设计问题,我不希望我的代码因为一个糟糕的解决方案而变得一团糟。我宁愿解释我的确切情况,也不愿作一个很差的类比。

    我正在尝试写一个wii-play坦克的克隆版本,我在设计坦克类时遇到了麻烦。 Tank 它本身是唯一这样的类,它对其部分使用依赖注入。现在这两部分是 TankAI TankWeapon . 人工智能处理关于运动和射击的决定,武器描述了武器的行为——它发射的是什么抛射物,以及多久发射一次,等等。我有一个工厂级,以不同的组合建造坦克。

    我的抛射体类是在抽象的 Projectile 类。每个子类描述射弹的模型、弹跳次数、速度等。

    我现在的问题是 坦克武器 子类在构建一个新的抛射体的区域周围复制了许多代码,因为它们每个都构建了一个不同的类。我想把这段代码移到基类中,但是我必须以某种方式注入这个武器需要构造的抛射体类本身。我知道我真的可以通过一个班的基础上建设,但这感觉是错误的方式去做。

    当我们在这里的时候,我还有另一个设计问题:我如何让我的人工智能类也知道抛射类?他们的决定将取决于所发射的炮弹的属性,例如它们能从墙上弹回多少次。人工智能和武器类都被提供给父类参考 坦克 注射后。

    编辑:

    看起来我最初的问题有点混乱,所以我会发布代码。我已经为我的坦克设置了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--;
        }
    }
    
    3 回复  |  直到 14 年前
        1
  •  2
  •   µBio    14 年前

    对于第一个问题,听起来你需要 ProjectileFactory 看起来像是

    // somewhere in tank weapon's Fire method or whatever
    Projectile p = projectileFactory.Create( myProjectile.GetType() );
    

    对于第二个问题,人工智能是否需要注入 Projectile 或A Type

    public Tank( TankAi ai, TankWeapon w) // ...
    public TankWeapon( Tank t, Projectile p ) // ...
    public TankAi( Tank t, Projectile p ) // ...
    public TankAi( Tank t, Type projectileType ) // ...
    

    问题 对于你……为什么武器和人工智能会得到坦克的参考?

        2
  •  2
  •   CodexArcanum    14 年前

    听起来您没有使用足够的接口。它有助于思考行为(实现)和功能(公开的接口)之间的区别。

    您希望每个投射物、人工智能和武器以相同的方式工作(拥有相同的接口),但实现独特的行为,并具有一些共享的行为。一个典型的模型是拥有Iweapon、iProjective和iIntelligence接口,这些接口定义了这些对象的公开的公共面。然后,您将拥有实现接口的每个(例如,base抛射体)的基类,并为所有要使用的抛射体提供一些常见的行为。

    现在,在类的构造函数(或setter,或在任何地方)中,您将接受类型的接口。

    所以艾杜坦克老板的课可能看起来像

    public class AI_Tank_Boss : BaseTank
    
    public AI_Tank_Boss(IWeapon weapon, IInteligence ai)
    {
        this.Weapon = weapon;
        this.AI = ai;
    }
    

    现在,每个依赖于人工智能方法的坦克方法(可能是从人工智能和坦克发射的事件会寻找这些事件来做些什么?)可以实现使用该接口,任何特定于武器的代码都将调用Iweapon接口。

    什么 实际上发生了 基于特定的武器子类如何实现方法以及如何使用基本武器中的公共代码。这是多态性的基础,也是为什么注入可以工作的原因。

        3
  •  1
  •   Android Eve    14 年前

    在构建时将类传递给基础确实是错误的做法。 基类不应该知道它的派生类。 如果你“必须以某种方式注入武器需要构造的抛射体类本身”,这意味着你没有正确地设计你的类层次结构和方法。

    除非你在这里发布你需要通过的例子,否则我很难提供一个具体的解决方案。