TP2 — Interfaces, Polymorphism & Advanced OOP

This module demonstrates advanced object-oriented programming concepts in Java, focusing on interfaces, polymorphism, composition, and delegation patterns.

🧠 Key concepts (TP2 — at a glance)

  • Interface: a contract of behavior; enables multiple implementations and loose coupling.
  • Default methods: implement behavior inside interfaces to share code without a base class.
  • Inheritance: reuse via extends (is‑a relation); enables overriding; avoid deep hierarchies and prefer composition when possible.
  • Abstract class: cannot be instantiated; mixes abstract methods (contracts) with shared state/behavior; choose when you need partial implementation + state.
  • Polymorphism: treat different real types through the same declared type; behavior chosen at runtime.
  • Override vs Overload: overriding replaces inherited instance behavior (polymorphic); overloading provides multiple method signatures.
  • Composition: build behavior by combining objects rather than deep inheritance.
  • Delegation: forward work to a collaborator instead of inheriting; favors composition.
  • Liskov Substitution Principle (LSP): subtypes must be substitutable for their base types without breaking expected behavior.

📚 Learning Path

1. Interfaces & Contracts

Package: fr.univtln.bruno.samples.java101.tp2.api

Key Interfaces:

  • Drivable — Basic vehicle operations with default method
  • Maintainable — Maintenance operations
  • Electric — Electric vehicle capabilities
  • Rechargeable — Battery charging interface
  • Refuelable — Fuel tank interface

Concepts:

  • Interface as contract (behavior specification)
  • Default methods (Java 8+)
  • Multiple interface implementation
  • Interface segregation principle
  • Marker interfaces

Why interfaces?

  • Define behavior without implementation
  • Multiple inheritance of behavior
  • Loose coupling between components
  • Easy to mock for testing
  • Plugin architecture support

2. Abstract Classes & Hierarchy

Package: fr.univtln.bruno.samples.java101.tp2.model

Key Classes:

  • Vehicle — Base abstract class
  • MotorVehicle — Specialized abstract class for motor vehicles

Concepts:

  • Abstract classes for common behavior
  • Template method pattern
  • Protected constructors
  • Shared state across hierarchy
  • When to use abstract class vs interface

Abstract vs Interface:

  • Abstract: Partial implementation, shared state
  • Interface: Pure contract, no state

3. Concrete Implementations

Package: fr.univtln.bruno.samples.java101.tp2.impl

Vehicle Types:

  • Bike — Simple non-motor vehicle
  • ElectricBike — Electric-powered bike
  • Car — Gasoline-powered car
  • ElectricCar — Electric-powered car
  • ServiceCar — Special maintenance vehicle

Concepts:

  • Implementing multiple interfaces
  • Overriding abstract methods
  • Specialized behavior per type
  • State management (fuel, battery)
  • Covariant return types in copy() methods

4. Polymorphism in Action

Test: PolymorphismTest.java

Concepts Demonstrated:

Static vs Dynamic Binding

Vehicle v = new Car("C1");
v.category(); // Dynamic dispatch

Interface Polymorphism

Drivable vehicle = new Car("C1");
vehicle.drive(); // Interface method

Covariant Return Types

Car original = new Car("C1");
Car copy = original.copy(); // Returns Car, not Vehicle

Benefits:

  • Write code against abstractions
  • Swap implementations easily
  • Extensible design
  • Testability through mocking

5. Composition & Delegation

Classes:

  • Driver — Composes with Drivable
  • Manufacturer — Factory for vehicles

Concepts:

Composition over Inheritance

  • Driver has-a Drivable (not is-a)
  • Flexible runtime behavior changes
  • No tight coupling to hierarchy
  • Easier testing and mocking

Delegation Pattern

class Driver {
    private Drivable vehicle;

    String drive() {
        return vehicle.drive(); // Delegates to vehicle
    }
}

Why composition?

  • More flexible than inheritance
  • Avoid fragile base class problem
  • Support multiple behaviors
  • Runtime behavior changes

6. Default Methods & Conflicts

Test: DefaultMethodConflictTest.java

Concepts:

  • Default method implementation in interfaces
  • Conflict resolution when implementing multiple interfaces
  • Explicit disambiguation with Interface.super.method()

Example:

interface A { default String m() { return "A"; } }
interface B { default String m() { return "B"; } }

class C implements A, B {
    @Override
    public String m() {
        return A.super.m(); // Explicit choice
    }
}

7. Interface Segregation

Test: InterfaceSegregationTest.java

Principle: Clients shouldn't depend on interfaces they don't use.

Good Design:

// Segregated interfaces
interface Drivable { void drive(); }
interface Refuelable { void refuel(); }

// Classes implement only what they need
class ElectricCar implements Drivable, Rechargeable { }
class GasCar implements Drivable, Refuelable { }

Bad Design:

// Fat interface
interface Vehicle {
    void drive();
    void refuel();   // Not all vehicles refuel!
    void charge();   // Not all vehicles charge!
}

8. Static Hiding (Not Polymorphism!)

Test: StaticHidingTest.java

Important: Static methods are NOT polymorphic!

class Vehicle {
    static String category() { return "Vehicle"; }
}

class Car extends Vehicle {
    static String category() { return "Car"; }  // HIDING, not overriding
}

Vehicle v = new Car();
v.category(); // Calls Vehicle.category(), not Car.category()!

Key Lesson: Use instance methods for polymorphism.


🧪 Testing & Coverage

Test Classes:

  • VehicleTest — Basic vehicle operations
  • PolymorphismTest — Dynamic dispatch examples
  • CompositionTest — Composition pattern
  • DelegationTest — Delegation pattern
  • InterfaceSegregationTest — ISP principle
  • DescriptionTest — Default method usage
  • CovariantReturnTest — Return type covariance
  • DefaultMethodConflictTest — Multiple interface conflicts
  • StaticHidingTest — Static method hiding
  • ResourceStateTest — State management (fuel, battery)

Run tests:

../../mvnw test

📊 Reports & Documentation


💡 Key Takeaways

Design Principles

  1. Program to interfaces, not implementations

    • Depend on abstractions
    • Swap implementations easily
  2. Favor composition over inheritance

    • More flexible
    • Avoid coupling
  3. Interface Segregation Principle

    • Many small interfaces > one large interface
    • Clients use only what they need
  4. Liskov Substitution Principle

    • Subtypes must be substitutable for base types
    • Maintain behavioral contracts

When to Use What

Pattern Use When
Interface Define pure contract, multiple implementations
Abstract Class Share implementation + state across hierarchy
Composition Need flexible behavior, avoid inheritance
Default Methods Add methods to existing interfaces without breaking clients

🎓 For Students

Recommended Study Order:

  1. Start with interfaces (api package)

    • Understand contracts
    • See default methods
  2. Explore abstract classes (model package)

    • Compare with interfaces
    • Understand template pattern
  3. Study implementations (impl package)

    • See polymorphism in action
    • Different vehicle types
  4. Run tests (test package)

    • See patterns in use
    • Understand edge cases
  5. Experiment

    • Add new vehicle types
    • Create new interfaces
    • Try different compositions

🔗 Navigation