SOLID, Explained With Fighter-Jet Code

The five SOLID principles — each a one-line rule, a jet analogy, and bad-vs-good code, all themed around a PvP dogfight game.

Karan Batra / /
SOLID, Explained With Fighter-Jet Code

Five rules for arranging classes so change stays cheap. Every example is pulled from the same world — a PvP fighter-jet dogfight game. Rule, analogy, then the code.

S — Single Responsibility

One class, one reason to change.

A jet keeps its systems apart: flight controls fly it, the weapons system fires, the radar scans, the flight recorder logs the mission. Swap the missile and only the weapons system is opened up.

// Bad — one Jet, four reasons to change
public class Jet
{
    public void Fly(Vector3 dir) { }
    public void FireMissile(Jet target) { }
    public void UpdateRadar() { }
    public void SaveToDisk() { }
}

// Good — one job each
public class FlightController { public void Fly(Vector3 dir) { } }
public class WeaponSystem     { public void FireMissile(Jet target) { } }
public class RadarSystem      { public void Scan() { } }
public class JetSaveService   { public void Save(Jet jet) { } }

O — Open/Closed

Open to extend, closed to modify.

Wing hardpoints: bolt on a new missile, don’t cut open the wing.

// Bad — every new weapon edits the same switch
public void Fire(string weapon, Jet target)
{
    switch (weapon)
    {
        case "cannon":  break;
        case "missile": break;
        // railgun? crack this open again
    }
}

// Good — fixed contract, new weapon = new class
public interface IWeapon { void Fire(Jet target); }

public class Cannon  : IWeapon { public void Fire(Jet t) { } }
public class Missile : IWeapon { public void Fire(Jet t) { } }
public class Railgun : IWeapon { public void Fire(Jet t) { } } // nothing else touched

public class WeaponSystem
{
    public void Fire(IWeapon weapon, Jet target) => weapon.Fire(target);
}

L — Liskov Substitution

A subtype must stand in for its base without surprises.

A flare can’t damage a target — so it isn’t a weapon.

// Bad — Flare lies about being a weapon
public class Flare : IWeapon
{
    public void Fire(Jet target) => throw new NotSupportedException();
}

// Good — model it as what it is
public interface IWeapon         { void Fire(Jet target); }
public interface ICountermeasure { void Deploy(); }

public class Flare : ICountermeasure { public void Deploy() { } }

I — Interface Segregation

Don’t force a class to implement methods it doesn’t use.

Give each cockpit only the controls its airframe has. No dead switches.

// Bad — one fat interface, dead buttons
public interface ICombatant
{
    void Fire(Jet target);
    void DeployFlare();
    void Cloak();   // only stealth jets have this
}

public class TrainerJet : ICombatant
{
    public void Cloak() => throw new NotImplementedException();
}

// Good — small role interfaces
public interface IAttacker { void Fire(Jet target); }
public interface IDefender { void DeployFlare(); }
public interface IStealth  { void Cloak(); }

public class TrainerJet : IAttacker, IDefender { }
public class StealthJet : IAttacker, IDefender, IStealth { }

D — Dependency Inversion

Depend on the abstraction, not the concrete detail.

The trigger fires whatever missile is loaded on the rail — it’s not welded to one.

// Bad — welded to one missile
public class WeaponSystem
{
    private readonly Aim9Missile missile = new Aim9Missile();
    public void Fire(Jet target) => missile.Launch(target);
}

// Good — any missile that fits the hardpoint
public interface IMissile { void Launch(Jet target); }

public class Aim9Missile  : IMissile { public void Launch(Jet t) { } }
public class RadarMissile : IMissile { public void Launch(Jet t) { } }

public class WeaponSystem
{
    private readonly IMissile missile;
    public WeaponSystem(IMissile missile) => this.missile = missile;
    public void Fire(Jet target) => missile.Launch(target);
}
Want to talk? Schedule a Call
Enjoyed this post? Subscribe on Substack
Karan Batra - Game Programmer
Karan Batra

Game Programmer & Co-Founder of PixelPunch LLP. I ship games, build tools, and make the web work harder.

Know more →