Я борюсь с проблемой дизайна и не хочу, чтобы мой код стал беспорядочным из-за плохого решения. Вместо того, чтобы привести плохую аналогию, я просто объясню свой точный случай.
Я пытаюсь написать клон Wii Play Tanks, и у меня возникают проблемы при разработке классов Tank. Tank
сам по себе является единственным таким классом, он использует внедрение зависимостей для своих частей. Сейчас две части - TankAI
и TankWeapon
. ИИ принимает решения о движении и стрельбе, оружие описывает, как ведет себя оружие - какие снаряды оно стреляет, как часто и т. Д. У меня есть заводской класс, который строит танки в различных комбинациях.
Мои классы снарядов настроены на абстрактный Projectile
класс. Каждый подкласс описывает модель снаряда, количество отскоков, скорость и т. Д.
Проблема, с которой я столкнулся, заключается в том, что каждый подкласс TankWeapon
дублирует много кода вокруг области, где они создают новый снаряд, потому что каждый из них создает свой класс. Я хочу переместить этот код в базовый класс, но мне нужно было бы каким-то образом внедрить сам класс снарядов, который необходимо создать оружию. Я знаю, что могу буквально передать Класс на базу при строительстве, но это похоже на неправильный путь.
И пока мы занимаемся этим, у меня возникает еще одна проблема: как я могу заставить свои классы ИИ знать о классе снарядов? Их решения будут зависеть от свойств метательного снаряда, например, от того, сколько раз они могут отскочить от стен. Классы ИИ и Оружия получают ссылку на родителя Tank
после инъекции.
Edit:
Кажется, мой первоначальный вопрос был немного запутанным, поэтому я опубликую код. У меня уже есть 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--;
}
}