Lecture 14: Facade Pattern - Concealing Complexity

๐Ÿ›๏ธ Facade Pattern

Concealing Complexity with a Facade

Game Programming - CSCI 3213

Spring 2026 - Lecture 14

๐Ÿ“š Learning Objectives

Developer's Note: "Never Panic Early"

โš ๏ธ What to Expect During Implementation

As we implement this pattern, we'll be creating multiple files in a specific order. You will see errors in Unity and your IDE until all files are complete.

How to Handle Development Errors

  • Don't Ignore: Note the errors - they're telling you something
  • Don't Panic: These are expected until all files are created
  • Stay Calm: Follow the implementation order and errors will resolve

As Apollo 13's Fred Haise said: "Never Panic Early"

This is a critical skill for software development. Note problems, but stay focused on the implementation path.

๐ŸŒ Real-World Analogy

Starting Your Car

Think about what happens when you turn the ignition key:

Behind the Scenes (Complex):

  • Battery sends electrical current to starter motor
  • Starter motor cranks the engine
  • Fuel pump activates, sending gas to cylinders
  • Spark plugs ignite fuel-air mixture
  • Pistons start moving, crankshaft rotates
  • Cooling system activates to prevent overheating
  • Oil pump circulates lubricant

What You Do (Simple):

Turn the key. ๐Ÿ”‘

The Pattern: The ignition system is a facade that hides complex engine subsystems behind a simple interface

๐Ÿ” Understanding the Facade Pattern

Core Concept

Provide a unified, simplified interface to a set of interfaces in a subsystem, making the subsystem easier to use.

Key Characteristics:

  • Single class acts as simplified interface
  • Wraps complex subsystem interactions
  • Client doesn't know about subsystem details
  • Reduces coupling between client and subsystem
  • Doesn't prevent direct subsystem access (optional)

The Problem It Solves

Your game has multiple complex, interacting systems. Clients need to use these systems but shouldn't need to understand their intricate interactions.

Pattern Type: Structural - concerned with composing classes into larger structures

โš–๏ธ Facade vs Adapter Pattern

Aspect Facade Pattern Adapter Pattern
Intent Simplify complex interface Convert incompatible interface
Interface Creates NEW simplified interface Adapts EXISTING interface to match target
Number of Classes Wraps multiple subsystems Usually adapts one class
Goal Ease of use Compatibility
Key Difference: Facade establishes a new interface; Adapter adapts an old interface

๐Ÿ—๏ธ Facade Pattern Structure

Key Participants:

Flow:

Client โ†’ Facade.TurnOn() โ†’ FuelPump.Start()
                         โ†’ CoolingSystem.Start()
                         โ†’ Internal orchestration
                    

โœ… Benefits of Facade Pattern

โš ๏ธ Potential Drawbacks

Warning: Use facades to simplify, not to hide bad design!

๐ŸŽฏ When to Use Facade Pattern

Use Facade When:

Don't Use Facade When:

Common Game Use Cases:

๐Ÿ๏ธ Use Case: High-Speed Bike Engine

Design Goal:

Simulate a motorcycle engine with realistic component interactions, but expose a simple interface for gameplay.

Engine Components (Subsystems):

  • Fuel Pump:
    • Manages fuel consumption
    • Tracks remaining fuel
    • Stops engine when fuel depleted
  • Cooling System:
    • Prevents engine overheating
    • Shuts down during turbo (power relay)
    • Stops engine if temperature exceeds max
  • Turbo Charger:
    • Temporarily increases top speed
    • Disables cooling system when active
    • Limited duration
Risk vs Reward: Turbo makes you faster but risks overheating!

๐Ÿ’ป FuelPump Subsystem (1/2)

๐Ÿ“ File Structure Note

Create a new file: FuelPump.cs
Subsystem component that manages fuel consumption.

using UnityEngine; using System.Collections; public class FuelPump : MonoBehaviour { public BikeEngine engine; public IEnumerator burnFuel; void Start() { burnFuel = BurnFuel(); }

Key Points:

  • References the engine facade
  • Stores coroutine reference for stopping
  • Initialized on Start()

๐Ÿ’ป FuelPump Subsystem (2/2)

IEnumerator BurnFuel() { while (true) { yield return new WaitForSeconds(1); engine.fuelAmount -= engine.burnRate; if (engine.fuelAmount <= 0.0f) { engine.TurnOff(); yield return 0; } } } void OnGUI() { GUI.color = Color.green; GUI.Label(new Rect(100, 40, 500, 20), "Fuel: " + engine.fuelAmount); } }
Behavior: Burns fuel every second, stops engine when depleted

๐Ÿ’ป CoolingSystem Subsystem (1/2)

๐Ÿ“ File Structure Note - PRODUCTION CODE

Create a new file: Assets/Scripts/Subsystems/CoolingSystem.cs
This subsystem manages engine cooling for the bike.
โš ๏ธ This code goes into your Unity project for Blade Racer.

using UnityEngine; using System.Collections; public class CoolingSystem : MonoBehaviour { public BikeEngine engine; public IEnumerator coolEngine; private bool _isPaused; void Start() { coolEngine = CoolEngine(); } public void PauseCooling() { _isPaused = !_isPaused; } public void ResetTemperature() { engine.currentTemp = 0.0f; }

๐Ÿ’ป CoolingSystem Subsystem (2/2)

๐Ÿ“ Continuing CoolingSystem.cs

Add this coroutine method to the CoolingSystem class from the previous slide.

IEnumerator CoolEngine() { while (true) { yield return new WaitForSeconds(1); if (!_isPaused) { // Cool toward ideal temperature if (engine.currentTemp > engine.minTemp) engine.currentTemp -= engine.tempRate; if (engine.currentTemp < engine.minTemp) engine.currentTemp += engine.tempRate; } else { // Paused = heating up! engine.currentTemp += engine.tempRate; } // Overheat protection if (engine.currentTemp > engine.maxTemp) engine.TurnOff(); } }

๐Ÿ’ป TurboCharger Subsystem

๐Ÿ“ File Structure Note - PRODUCTION CODE

Create a new file: Assets/Scripts/Subsystems/TurboCharger.cs
This subsystem manages turbo boost functionality for the bike.
โš ๏ธ This code goes into your Unity project for Blade Racer.

using UnityEngine; using System.Collections; public class TurboCharger : MonoBehaviour { public BikeEngine engine; private bool _isTurboOn; private CoolingSystem _coolingSystem; public void ToggleTurbo(CoolingSystem coolingSystem) { _coolingSystem = coolingSystem; if (!_isTurboOn) StartCoroutine(TurboCharge()); } IEnumerator TurboCharge() { _isTurboOn = true; _coolingSystem.PauseCooling(); // DISABLE COOLING! yield return new WaitForSeconds(engine.turboDuration); _isTurboOn = false; _coolingSystem.PauseCooling(); // RE-ENABLE COOLING } }

๐Ÿ’ป BikeEngine Facade (1/4)

๐Ÿ“ File Structure Note

Create a new file: BikeEngine.cs
Facade class that simplifies interaction with engine subsystems.

using UnityEngine; public class BikeEngine : MonoBehaviour { // Engine parameters (exposed to subsystems) public float burnRate = 1.0f; public float fuelAmount = 100.0f; public float tempRate = 5.0f; public float minTemp = 50.0f; public float maxTemp = 65.0f; public float currentTemp; public float turboDuration = 2.0f; private bool _isEngineOn; private FuelPump _fuelPump; private TurboCharger _turboCharger; private CoolingSystem _coolingSystem;
Design: Facade owns and configures all subsystems

๐Ÿ’ป BikeEngine Facade (2/4)

void Awake() { // Create subsystem components _fuelPump = gameObject.AddComponent(); _turboCharger = gameObject.AddComponent(); _coolingSystem = gameObject.AddComponent(); } void Start() { // Wire up subsystem references _fuelPump.engine = this; _turboCharger.engine = this; _coolingSystem.engine = this; }

Initialization:

  • Awake(): Create subsystem components
  • Start(): Configure subsystem dependencies
  • All subsystems reference the facade

๐Ÿ’ป BikeEngine Facade (3/4) - The Interface!

// SIMPLIFIED PUBLIC INTERFACE public void TurnOn() { _isEngineOn = true; StartCoroutine(_fuelPump.burnFuel); StartCoroutine(_coolingSystem.coolEngine); } public void TurnOff() { _isEngineOn = false; _coolingSystem.ResetTemperature(); StopCoroutine(_fuelPump.burnFuel); StopCoroutine(_coolingSystem.coolEngine); } public void ToggleTurbo() { if (_isEngineOn) _turboCharger.ToggleTurbo(_coolingSystem); }
Key: Three simple methods hide all subsystem complexity!

๐Ÿ’ป BikeEngine Facade (4/4)

void OnGUI() { GUI.color = Color.green; GUI.Label( new Rect(100, 0, 500, 20), "Engine Running: " + _isEngineOn); } }

What the Facade Hides:

  • Component initialization and configuration
  • Coroutine management
  • Inter-subsystem communication (turbo โ†” cooling)
  • Parameter passing between systems
  • Startup/shutdown sequences

๐Ÿ’ป ClientFacade - Simple Usage

๐Ÿ“ File Structure Note - TESTING CODE

Create a new file: Assets/Scripts/Testing/ClientFacade.cs
This script tests your Facade pattern implementation with GUI buttons.
โš ๏ธ This is temporary testing code - you can remove it after testing your implementation.

using UnityEngine; public class ClientFacade : MonoBehaviour { private BikeEngine _bikeEngine; void Start() { _bikeEngine = gameObject.AddComponent(); } void OnGUI() { if (GUILayout.Button("Turn On")) _bikeEngine.TurnOn(); if (GUILayout.Button("Turn Off")) _bikeEngine.TurnOff(); if (GUILayout.Button("Toggle Turbo")) _bikeEngine.ToggleTurbo(); } }
๐Ÿ’ก Alternative: When you have multiple test scripts with overlapping GUI buttons, consider using TestPanel.cs to combine all test controls into one draggable window. See the Event Bus lecture for the unified TestPanel implementation.
Beauty: Client has NO knowledge of FuelPump, CoolingSystem, or TurboCharger!

๐ŸŽฎ Updating TestPanel for Facade Pattern

๐Ÿ“ Evolving TestPanel.cs

Add Facade Pattern keyboard shortcuts and section to your TestPanel.cs.

// Add to TestPanel fields private bool _facadeExpanded = true; private BikeEngine _bikeEngine; void Start() { // ... existing code ... _bikeEngine = FindFirstObjectByType<BikeEngine>(); } // Add to Update() - Facade Pattern shortcuts if (_bikeEngine != null) { if (Input.GetKeyDown(KeyCode.O)) // O = On _bikeEngine.TurnOn(); if (Input.GetKeyDown(KeyCode.I)) // I = off (I looks like |) _bikeEngine.TurnOff(); if (Input.GetKeyDown(KeyCode.U)) // U = tUrbo _bikeEngine.ToggleTurbo(); }
// Add DrawFacadeSection() method void DrawFacadeSection() { if (_bikeEngine == null) return; GUI.backgroundColor = new Color(0.8f, 0.4f, 0f); // Brown _facadeExpanded = GUILayout.Toggle( _facadeExpanded, "โ–ผ Facade Pattern", "button"); GUI.backgroundColor = Color.white; if (_facadeExpanded) { GUILayout.BeginVertical("box"); if (GUILayout.Button("Turn On (O)")) _bikeEngine.TurnOn(); if (GUILayout.Button("Turn Off (I)")) _bikeEngine.TurnOff(); if (GUILayout.Button("Toggle Turbo (U)")) _bikeEngine.ToggleTurbo(); GUILayout.EndVertical(); } }
Keymap Update: Add to DrawKeymapWindow():
O = Turn On, I = Turn Off, U = Toggle Turbo

๐ŸŽฏ The Power of Abstraction

Without Facade:

// Client needs to know EVERYTHING var fuelPump = gameObject.AddComponent(); var coolingSystem = gameObject.AddComponent(); var turboCharger = gameObject.AddComponent(); fuelPump.engine = this; coolingSystem.engine = this; turboCharger.engine = this; StartCoroutine(fuelPump.burnFuel); StartCoroutine(coolingSystem.coolEngine); // ... and on and on ...

With Facade:

// Client just uses the engine _bikeEngine.TurnOn();
Result: ~20 lines reduced to 1 line!

๐Ÿงช Testing the Implementation

Steps:

  1. Create new Unity scene
  2. Create empty GameObject named "BikeEngineTest"
  3. Attach ClientFacade script
  4. Press Play
  5. Click "Turn On" button
  6. Watch fuel decrease and temperature regulate
  7. Click "Toggle Turbo" - see cooling pause
  8. Wait for fuel to run out or engine to overheat
Expected Behavior:
  • Fuel decreases over time
  • Temperature regulates around minTemp
  • Turbo causes temperature to spike
  • Engine stops when fuel = 0 or temp > maxTemp

๐Ÿ”ง Adding New Components

Example: Add Nitro Injector

// 1. Create new subsystem public class NitroInjector : MonoBehaviour { public BikeEngine engine; public void InjectNitro() { // Massive speed boost! // Huge fuel consumption! // Temperature spike! } } // 2. Update facade public class BikeEngine : MonoBehaviour { private NitroInjector _nitroInjector; void Awake() { // ... existing code ... _nitroInjector = gameObject.AddComponent(); } public void ActivateNitro() { if (_isEngineOn) _nitroInjector.InjectNitro(); } }
Key: Client code doesn't change - just exposes new method!

๐ŸŽฎ Connecting to Bike Movement

public class BikeController : MonoBehaviour { private BikeEngine _engine; private Rigidbody _rb; public float normalSpeed = 10f; public float turboMultiplier = 2f; void Start() { _engine = GetComponent(); _rb = GetComponent(); _engine.TurnOn(); } void Update() { // Can't move if engine is off if (!_engine.IsEngineOn) { _rb.velocity = Vector3.zero; return; } // Normal movement float speed = normalSpeed; // Turbo boost! if (Input.GetKeyDown(KeyCode.Space)) _engine.ToggleTurbo(); if (_engine.IsTurboActive) speed *= turboMultiplier; // Move bike... _rb.velocity = transform.forward * speed; } }

๐Ÿ“Š Engine Status UI

using UnityEngine; using UnityEngine.UI; public class EngineUI : MonoBehaviour { public BikeEngine engine; public Slider fuelGauge; public Slider tempGauge; public Text statusText; public Image turboIndicator; void Update() { // Update fuel gauge fuelGauge.value = engine.fuelAmount / 100f; // Update temperature gauge tempGauge.value = (engine.currentTemp - engine.minTemp) / (engine.maxTemp - engine.minTemp); // Color temperature gauge based on danger if (tempGauge.value > 0.8f) tempGauge.fillRect.GetComponent().color = Color.red; else if (tempGauge.value > 0.5f) tempGauge.fillRect.GetComponent().color = Color.yellow; else tempGauge.fillRect.GetComponent().color = Color.green; // Update status statusText.text = engine.IsEngineOn ? "ENGINE ON" : "ENGINE OFF"; // Turbo indicator turboIndicator.enabled = engine.IsTurboActive; } }

โš™๏ธ Enhanced Engine System

Additional Subsystems to Consider:

Facade handles them all: Client still just calls TurnOn(), TurnOff(), ToggleTurbo()

๐Ÿ”„ Alternative Patterns to Consider

Before Using Facade, Consider:

๐Ÿšซ Common Mistakes to Avoid

  1. Using Facade to Hide Bad Code:
    // BAD - Facade hiding spaghetti code public void DoEverything() { // 500 lines of messy logic } // GOOD - Facade coordinating clean subsystems public void StartGame() { _levelLoader.Load(); _playerSpawner.Spawn(); _uiManager.ShowHUD(); }
  2. Too Many Manager Classes:
    • โŒ GameManager, LevelManager, PlayerManager, EnemyManager...
    • โœ… Use facades sparingly, only where needed
  3. Leaky Abstraction:
    // BAD - Exposing subsystem details public FuelPump GetFuelPump() { return _fuelPump; } // GOOD - Exposing only needed info public float GetFuelPercent() { return fuelAmount / maxFuel; }
  4. Overly Complex Facade:
    • If facade has 50+ methods, reconsider design
    • Might need multiple smaller facades

๐Ÿงช Unit Testing Strategies

using NUnit.Framework; using UnityEngine; [Test] public void BikeEngine_TurnOn_StartsFuelBurning() { // Arrange var go = new GameObject(); var engine = go.AddComponent(); float initialFuel = engine.fuelAmount; // Act engine.TurnOn(); yield return new WaitForSeconds(2f); // Assert Assert.Less(engine.fuelAmount, initialFuel); } [Test] public void BikeEngine_ToggleTurbo_IncreasesTemperature() { // Arrange var go = new GameObject(); var engine = go.AddComponent(); engine.TurnOn(); float initialTemp = engine.currentTemp; // Act engine.ToggleTurbo(); yield return new WaitForSeconds(1f); // Assert Assert.Greater(engine.currentTemp, initialTemp); } [Test] public void BikeEngine_OutOfFuel_StopsEngine() { // Arrange var go = new GameObject(); var engine = go.AddComponent(); engine.fuelAmount = 1f; engine.TurnOn(); // Act yield return new WaitForSeconds(2f); // Assert Assert.IsFalse(engine.IsEngineOn); }

๐Ÿ› Debugging Tips

Add Logging to Facade:

public void TurnOn() { Debug.Log("[BikeEngine] TurnOn() called"); _isEngineOn = true; Debug.Log("[BikeEngine] Starting FuelPump coroutine"); StartCoroutine(_fuelPump.burnFuel); Debug.Log("[BikeEngine] Starting CoolingSystem coroutine"); StartCoroutine(_coolingSystem.coolEngine); Debug.Log("[BikeEngine] Engine is now running"); }

Visual Debugging:

void OnDrawGizmos() { if (_isEngineOn) Gizmos.color = Color.green; else Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, 1f); }

โšก Performance Tips

Optimization Strategies:

๐ŸŽฏ Facade + Singleton (Use Carefully!)

Common Unity Pattern:

public class GameManager : MonoBehaviour { public static GameManager Instance { get; private set; } private AudioSystem _audio; private InputSystem _input; private SaveSystem _save; void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); // Initialize subsystems _audio = new AudioSystem(); _input = new InputSystem(); _save = new SaveSystem(); } // Simplified facade methods public void PlaySound(string name) => _audio.Play(name); public float GetAxis(string name) => _input.GetAxis(name); public void SaveGame() => _save.Save(); }
Warning: Don't abuse this pattern - creates global dependencies!

๐ŸŽฎ Real-World Game Applications

Facade Pattern in Production Games:

๐Ÿ—๏ธ Facade in Layered Architecture

Organizing Your Game:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Presentation Layer (UI)          โ”‚
โ”‚    - Buttons, Menus, HUD             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Facade Layer (Managers)          โ”‚ โ† Simplified Interface
โ”‚    - GameManager                     โ”‚
โ”‚    - LevelManager                    โ”‚
โ”‚    - PlayerManager                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Business Logic Layer              โ”‚
โ”‚    - Game rules, systems             โ”‚
โ”‚    - Physics, AI, progression        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Data Layer                        โ”‚
โ”‚    - Save files, databases           โ”‚
โ”‚    - Assets, configuration           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    
Benefit: Each layer only knows about the layer below through facades

๐Ÿ”ง Using Facades for Refactoring

Gradual Improvement Strategy:

Step 1: Create Facade for Messy Code

// Wrap existing messy system public class LegacyInventoryFacade { private OldMessyInventory _legacy = new OldMessyInventory(); public void AddItem(string item) { // Simple interface hides complexity _legacy.DoComplicatedThingToAddItem(item, true, null, 0); } }

Step 2: Replace Client Dependencies

// Change all client code to use facade // Before: OldMessyInventory inventory; // After: LegacyInventoryFacade inventory;

Step 3: Refactor Behind Facade

// Replace implementation, keep interface public class LegacyInventoryFacade { private NewCleanInventory _new = new NewCleanInventory(); public void AddItem(string item) { _new.Add(item); // Much better! } }

Step 4: Remove "Legacy" Prefix

๐Ÿ“ Summary

What We Learned:

Key Takeaways:

Gaming History Moment ๐Ÿ•น๏ธ

PlayStation Origin Story: The Failed Partnership (1991-1994)

In 1988, Sony and Nintendo partnered to create a CD-ROM add-on for the SNES called the "Play Station." At 1991 CES, Sony announced the partnership. The next day, Nintendo publicly announced they'd partnered with Philips instead, humiliating Sony on the world stage. Sony executives wanted to abandon gaming entirely, but engineer Ken Kutaragi convinced them to proceed alone.

The result was the PlayStation (1994). Its secret weapon? A simple, unified development environment. While Saturn and N64 had complex multi-chip architectures requiring assembly code, PlayStation offered a clean C library facade. Developers called simple functions like LoadTexture() or PlayAudio(), and Sony's SDK handled the messy hardware details. This facade made development so easy that third-party devs flocked to PlayStation, giving it 102 million sales.

Connection to Facade Pattern

PlayStation's SDK was a Facade Pattern triumph! Behind the scenes, the hardware had complex subsystems - graphics chips, sound processors, CD-ROM controllers - each with intricate APIs. Sony's SDK provided a facade: simple, high-level functions that hid this complexity. Just like our BikeEngineFacade wraps FuelSystem, CoolingSystem, and TurboSystem into one simple interface, PlayStation's SDK wrapped GPU, SPU, and CD subsystems. The facade didn't limit power - experts could still access low-level APIs - it just made common tasks simple!

Learn More: From Pixels to Polygons: The Story of PlayStation | The Making of PlayStation

๐Ÿ’ช Practice Exercise

Build a Character Combat System Facade

Requirements:

  1. Create subsystem classes:
    • HealthSystem: Track HP, handle damage, death
    • StaminaSystem: Track stamina, regeneration, depletion
    • WeaponSystem: Manage equipped weapon, durability
    • DefenseSystem: Armor, blocking, dodge
  2. Create CombatFacade with methods:
    • Attack() - costs stamina, uses weapon
    • Defend() - costs stamina, reduces damage
    • TakeDamage(float amount) - applies armor, affects health
    • Rest() - restore stamina faster
  3. Client should only interact with facade, not subsystems
  4. Add UI to display health, stamina, weapon durability
Bonus: Add special move that costs both health and stamina

๐Ÿ“š Additional Resources

Further Reading:

Unity Resources:

Related Patterns:

๐Ÿš€ Looking Ahead

Course Progress:

Design Patterns Covered:

Final Project Ideas Using Facade:

โ“ Questions?

Common Questions:

  • Q: Should I always use facades for complex systems?
    • A: Only if the complexity is worth abstracting. Don't over-engineer simple systems.
  • Q: Can clients access subsystems directly?
    • A: Yes! Facade doesn't prevent it, just provides simpler alternative.
  • Q: Difference between Facade and God Object anti-pattern?
    • A: Facade delegates to subsystems. God Object does everything itself.
  • Q: Should facade be a Singleton?
    • A: Only if truly needed globally. Often better as instance or dependency injection.
  • Q: How many methods should a facade have?
    • A: As few as possible. If 20+, consider splitting into multiple facades.
  • Q: Can subsystems use the facade?
    • A: Generally no - creates circular dependencies. Use Mediator instead.

Thank you! ๐ŸŽฎ