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 methodMaintainable— Maintenance operationsElectric— Electric vehicle capabilitiesRechargeable— Battery charging interfaceRefuelable— 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 classMotorVehicle— 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 vehicleElectricBike— Electric-powered bikeCar— Gasoline-powered carElectricCar— Electric-powered carServiceCar— 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 withDrivableManufacturer— Factory for vehicles
Concepts:
Composition over Inheritance
Driverhas-aDrivable(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 operationsPolymorphismTest— Dynamic dispatch examplesCompositionTest— Composition patternDelegationTest— Delegation patternInterfaceSegregationTest— ISP principleDescriptionTest— Default method usageCovariantReturnTest— Return type covarianceDefaultMethodConflictTest— Multiple interface conflictsStaticHidingTest— Static method hidingResourceStateTest— State management (fuel, battery)
Run tests:
../../mvnw test
📊 Reports & Documentation
- Javadoc — Full API documentation
- Test Report — All test results
- JaCoCo Coverage — Code coverage metrics
- Checkstyle — Style compliance
- PMD — Code quality analysis
- SpotBugs — Potential bugs
💡 Key Takeaways
Design Principles
-
Program to interfaces, not implementations
- Depend on abstractions
- Swap implementations easily
-
Favor composition over inheritance
- More flexible
- Avoid coupling
-
Interface Segregation Principle
- Many small interfaces > one large interface
- Clients use only what they need
-
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:
-
Start with interfaces (
apipackage)- Understand contracts
- See default methods
-
Explore abstract classes (
modelpackage)- Compare with interfaces
- Understand template pattern
-
Study implementations (
implpackage)- See polymorphism in action
- Different vehicle types
-
Run tests (
testpackage)- See patterns in use
- Understand edge cases
-
Experiment
- Add new vehicle types
- Create new interfaces
- Try different compositions
