Course contentsShow
← Unity Game Development
Lesson 436 of 8287. Advanced Game ArchitectureFree lesson

Enforcing Liskov Substitution with Interface-Based Design

You will create interchangeable game objects that rely on shared interfaces, allowing varied systems to interact without knowing specific implementation details.

In this lesson, you will learn how to use interfaces to ensure that any game object can be swapped for another without breaking your systems, satisfying the Liskov Substitution Principle.

The Problem with Concrete Dependencies

Often, we find ourselves writing code that depends on specific classes. For example, if you have a PlayerHealth script, you might write an Explosion script that explicitly looks for PlayerHealth to call TakeDamage(). If you later want that explosion to also damage DestructibleCrate or EnemyAI, your code becomes cluttered with if-else checks or massive inheritance chains. This violates Liskov Substitution because these objects aren't truly interchangeable in the eyes of the Explosion script.

Designing with Interfaces

To fix this, we define a contract: an interface. An interface tells your system, "I don't care what you are, as long as you can perform this action."

First, define your interface:

public interface IDamageable {
    void TakeDamage(float amount);
}

Next, implement it across your different classes:

public class PlayerHealth : MonoBehaviour, IDamageable {
    public void TakeDamage(float amount) { /* Implementation */ }
}

public class DestructibleCrate : MonoBehaviour, IDamageable {
    public void TakeDamage(float amount) { /* Implementation */ }
}

Now, your Explosion script becomes completely decoupled:

public class Explosion : MonoBehaviour {
    void OnTriggerEnter(Collider other) {
        // We only care if the object implements IDamageable
        if (other.TryGetComponent(out IDamageable target)) {
            target.TakeDamage(10f);
        }
    }
}

Why This Matters

By using IDamageable, you satisfy the Liskov Substitution Principle: any class implementing IDamageable can be substituted for another without the Explosion script needing to know the implementation details. You can add infinite new types of damageable objects—or even "healing" objects that implement a similar pattern—without ever modifying the Explosion class again. This keeps your architecture clean, modular, and resilient to change.

Key Takeaway: Depend on interfaces rather than concrete classes to ensure that your game systems remain flexible and truly interchangeable.