🔌 Interfaces and Abstract Classes

Master Java's contract system and inheritance architecture through visual comparisons, design patterns, and real-world implementations


🎯 Learning Objectives

By the end of this lesson, you will:


🏛️ Contract Architecture Overview

<aside> 📋

Interface Philosophy

Interfaces are like business contracts - they define what must be done without specifying how to do it. Abstract classes are like architectural blueprints - they provide both the contract and some foundational implementation.

</aside>

The Contract vs Blueprint Comparison

Interface vs Abstract Class Architecture
══════════════════════════════════════════════════════════════════════════════════

         📋 INTERFACE                          🏗️ ABSTRACT CLASS
      ┌─────────────────┐                  ┌─────────────────────┐
      │     CONTRACT    │                  │     BLUEPRINT       │
      │                 │                  │                     │
      │ ✅ What to do   │                  │ ✅ What to do       │
      │ ❌ How to do it │                  │ ✅ How to do some   │
      │                 │                  │ ❌ How to do all    │
      │ • All abstract  │                  │                     │
      │ • Multiple      │                  │ • Mixed concrete    │
      │   inheritance   │                  │   & abstract        │
      │ • Pure contract │                  │ • Single inherit    │
      └─────────────────┘                  │ • Partial blueprint │
              │                            └─────────────────────┘
              ▼                                        ▼
    
    🎭 "CAN-DO" Behavior                    🧬 "IS-A" Relationship
    ┌─────────────────┐                  ┌─────────────────────┐
    │ Flyable         │                  │ Animal              │
    │ Swimmable       │                  │  ├─ Mammal          │
    │ Drawable        │                  │  ├─ Bird            │
    │ Serializable    │                  │  └─ Fish            │
    └─────────────────┘                  └─────────────────────┘
         Capabilities                          Family Tree

🎭 Interface Mastery

Modern Interface Architecture (Java 8+)

Complete Interface Structure - The Evolution
═════════════════════════════════════════════════════════════════════════════════

    📋 Modern Interface (Java 9+)
    ┌─────────────────────────────────────────┐
    │                                         │
    │ 🔸 Constants (public static final)      │ ← Always constant
    │ 🔸 Abstract methods (public abstract)   │ ← Must implement
    │ 🔸 Default methods (public default)     │ ← Can override  
    │ 🔸 Static methods (public static)       │ ← Call via Interface.method()
    │ 🔸 Private methods (private)            │ ← Helper methods (Java 9+)
    │                                         │
    └─────────────────────────────────────────┘
                          │
                          ▼
               📱 Implementation Classes
            ┌─────────────────────────────┐
            │ • Must implement abstract   │
            │ • Can override default      │
            │ • Cannot access private     │
            │ • Cannot override static    │
            └─────────────────────────────┘

🎮 Gaming System Interface Example

// 🎮 Modern gaming interface with all method types
public interface GameCharacter {
    
    // 🔸 Constants - shared game configuration
    String GAME_VERSION = "1.0.0";
    int MAX_LEVEL = 100;
    int DEFAULT_HEALTH = 100;
    
    // 🔸 Abstract methods - must be implemented by all characters
    void attack(GameCharacter target);
    void defend();
    int getHealth();
    int getLevel();
    
    // 🔸 Default methods - common behavior with option to override
    default void levelUp() {
        System.out.println(getName() + " leveled up to level " + (getLevel() + 1) + "!");
        restoreHealth();
        System.out.println("Health restored to full!");
    }
    
    default void restoreHealth() {
        System.out.println(getName() + " health restored to " + DEFAULT_HEALTH);
        // Implementation would set health to max
    }
    
    default void displayStats() {
        System.out.println("📊 Character Stats:");
        System.out.println("   Name: " + getName());
        System.out.println("   Level: " + getLevel());
        System.out.println("   Health: " + getHealth());
        System.out.println("   Type: " + getCharacterType());
    }
    
    default boolean isAlive() {
        return getHealth() > 0;
    }
    
    // 🔸 Static methods - utility methods for the interface
    static GameCharacter createRandomCharacter() {
        String[] types = {"Warrior", "Mage", "Archer", "Rogue"};
        String randomType = types[(int) (Math.random() * types.length)];
        
        System.out.println("🎲 Creating random " + randomType + " character...");
        
        return switch (randomType) {
            case "Warrior" -> new WarriorCharacter("RandomWarrior");
            case "Mage" -> new MageCharacter("RandomMage");
            case "Archer" -> new ArcherCharacter("RandomArcher");
            default -> new RogueCharacter("RandomRogue");
        };
    }
    
    static void printGameInfo() {
        System.out.println("🎮 Game Version: " + GAME_VERSION);
        System.out.println("🏆 Max Level: " + MAX_LEVEL);
        System.out.println("❤️ Default Health: " + DEFAULT_HEALTH);
    }
    
    static boolean isValidLevel(int level) {
        return level >= 1 && level <= MAX_LEVEL;
    }
    
    // 🔸 Private methods (Java 9+) - internal helpers
    private void logAction(String action) {
        System.out.println("[" + [java.time.LocalTime.now](<http://java.time.LocalTime.now>)() + "] " + 
                          getName() + " performed: " + action);
    }
    
    private String formatHealthBar() {
        int health = getHealth();
        int barLength = 20;
        int filledBars = (health * barLength) / DEFAULT_HEALTH;
        
        StringBuilder healthBar = new StringBuilder("[");
        for (int i = 0; i < barLength; i++) {
            if (i < filledBars) {
                healthBar.append("█");
            } else {
                healthBar.append("░");
            }
        }
        healthBar.append("]");
        return healthBar.toString();
    }
    
    // Abstract methods that need implementation
    String getName();
    String getCharacterType();
}

// 🗡️ Warrior Implementation
public class WarriorCharacter implements GameCharacter {
    private String name;
    private int level;
    private int health;
    private int armor;
    private String weapon;
    
    public WarriorCharacter(String name) {
        [this.name](<http://this.name>) = name;
        this.level = 1;
        [this.health](<http://this.health>) = DEFAULT_HEALTH;
        this.armor = 50;
        this.weapon = "Iron Sword";
    }
    
    @Override
    public void attack(GameCharacter target) {
        if (!isAlive()) {
            System.out.println("💀 " + name + " cannot attack - defeated!");
            return;
        }
        
        int damage = 25 + (level * 2);
        System.out.println("⚔️ " + name + " attacks " + target.getName() + 
                          " with " + weapon + " for " + damage + " damage!");
        
        // In a real game, this would reduce target's health
        if (target instanceof WarriorCharacter warrior) {
            warrior.takeDamage(damage);
        }
    }
    
    @Override
    public void defend() {
        System.out.println("🛡️ " + name + " raises shield! Armor: " + armor);
        // Defense implementation would reduce incoming damage
    }
    
    // Warrior-specific method
    public void takeDamage(int damage) {
        int actualDamage = Math.max(0, damage - (armor / 10));
        health -= actualDamage;
        health = Math.max(0, health);
        
        System.out.println("💥 " + name + " takes " + actualDamage + 
                          " damage (blocked " + (damage - actualDamage) + 
                          ") - Health: " + health);
    }
    
    // Warrior can override default levelUp behavior
    @Override
    public void levelUp() {
        GameCharacter.super.levelUp(); // Call default implementation
        
        // Add warrior-specific level up bonuses
        armor += 5;
        System.out.println("🛡️ Armor increased to " + armor + "!");
        
        if (level % 5 == 0) {
            upgradeWeapon();
        }
    }
    
    private void upgradeWeapon() {
        String[] weapons = {"Iron Sword", "Steel Sword", "Mithril Sword", "Legendary Blade"};
        int weaponIndex = Math.min(level / 5, weapons.length - 1);
        weapon = weapons[weaponIndex];
        System.out.println("⚔️ Weapon upgraded to " + weapon + "!");
    }
    
    // Required implementations
    @Override
    public String getName() { return name; }
    
    @Override
    public String getCharacterType() { return "Warrior"; }
    
    @Override
    public int getHealth() { return health; }
    
    @Override
    public int getLevel() { return level; }
    
    public int getArmor() { return armor; }
    public String getWeapon() { return weapon; }
}

// 🔮 Mage Implementation with different behavior
public class MageCharacter implements GameCharacter {
    private String name;
    private int level;
    private int health;
    private int mana;
    private String[] spells;
    
    public MageCharacter(String name) {
        [this.name](<http://this.name>) = name;
        this.level = 1;
        [this.health](<http://this.health>) = DEFAULT_HEALTH - 20; // Mages have less health
        this.mana = 100;
        this.spells = {"Magic Missile", "Fireball", "Lightning Bolt"};
    }
    
    @Override
    public void attack(GameCharacter target) {
        if (!isAlive()) {
            System.out.println("💀 " + name + " cannot cast - defeated!");
            return;
        }
        
        if (mana < 10) {
            System.out.println("🔮 " + name + " is out of mana!");
            return;
        }
        
        String spell = spells[(int) (Math.random() * spells.length)];
        int damage = 30 + (level * 3);
        mana -= 10;
        
        System.out.println("🔮 " + name + " casts " + spell + " at " + 
                          target.getName() + " for " + damage + " magic damage! (Mana: " + mana + ")");
    }
    
    @Override
    public void defend() {
        if (mana >= 15) {
            mana -= 15;
            System.out.println("✨ " + name + " casts Magic Shield! (Mana: " + mana + ")");
        } else {
            System.out.println("🏃 " + name + " attempts to dodge!");
        }
    }
    
    // Mage-specific mana restoration
    public void meditate() {
        mana = Math.min(100, mana + 25);
        System.out.println("🧘 " + name + " meditates and recovers mana: " + mana);
    }
    
    // Override default behavior for mages
    @Override
    public void levelUp() {
        GameCharacter.super.levelUp(); // Call default
        
        // Mage-specific bonuses
        mana += 20;
        System.out.println("🔮 Max mana increased to " + mana + "!");
        
        if (level % 3 == 0) {
            learnNewSpell();
        }
    }
    
    private void learnNewSpell() {
        String[] advancedSpells = {"Meteor", "Ice Storm", "Chain Lightning", "Teleport"};
        String newSpell = advancedSpells[(int) (Math.random() * advancedSpells.length)];
        System.out.println("📚 " + name + " learned new spell: " + newSpell + "!");
    }
    
    // Required implementations
    @Override
    public String getName() { return name; }
    
    @Override
    public String getCharacterType() { return "Mage"; }
    
    @Override
    public int getHealth() { return health; }
    
    @Override
    public int getLevel() { return level; }
    
    public int getMana() { return mana; }
}