In this lesson, you will learn how to prevent "fat" interfaces from forcing your components to implement unnecessary logic, keeping your codebase clean and modular.
The Problem of the Bloated Interface
When we use interfaces to define behavior, it’s tempting to group related methods together. For instance, consider an IDamageable interface that handles TakeDamage(), Heal(), and ApplyStatusEffect(). While these seem related, a simple crate might only need to take damage, while a poisoned trap might only need to apply a status effect. If you force the crate to implement Heal() and ApplyStatusEffect()—even if those methods are empty—you’ve created a violation of the Interface Segregation Principle. Your classes end up dependent on methods they don't actually use.
Segregating for Lean Components
To refine your architecture, break large interfaces into smaller, specialized ones. By splitting them, you allow components to opt-in only to the behaviors they actually support.
Instead of one IDamageable interface, try this:
public interface IDamageable {
void TakeDamage(float amount);
}
public interface IHealable {
void Heal(float amount);
}
public interface IStatusEffectable {
void ApplyStatus(EffectType type);
}
Now, a Player might implement all three, but a DestructibleCrate only implements IDamageable. Any system that interacts with these objects—like a grenade blast—can check specifically for IDamageable without caring if the object supports healing or status effects.
Why This Matters
When your components are lean, they are easier to debug and test. You no longer have empty method bodies cluttering your scripts, and your logic becomes strictly defined by what a component can do, rather than what it is forced to know about. This modularity makes swapping out gameplay features or extending systems significantly safer, as changes in one area (like adding a new status effect) won't require modifying unrelated classes that happened to share a bloated interface.
Key Takeaway: Never force a class to depend on methods it doesn't use; break down broad interfaces into small, specific contracts to keep your component logic clean and highly focused.