Abstract Classes and Interfaces Lesson

Abstract Classes and Interfaces

These two advanced OOP concepts are crucial for achieving abstraction. They allow us to define a "contract" for what a class must do, without specifying exactly how it should be done, leading to more flexible and powerful robot code.

Abstract Classes: A Partial Blueprint

An abstract class is a special type of class that cannot be instantiated on its own—you can't create an object from it. It serves as a base for other classes to inherit from, providing a mix of implemented and unimplemented methods.

When to Use an Abstract Class

Use an abstract class when you have a strong "is-a" relationship and want to provide some common, shared code. For example, an `Intake` is a `Mechanism`, and all mechanisms might share a common `getName()` method, but each will have a unique `run()` method.

// 1. The Abstract Superclass
// You cannot write 'new Mechanism()' - it's abstract.
public abstract class Mechanism {
    private String name;

    public Mechanism(String name) {
        this.name = name;
    }

    // A concrete method: it's fully implemented and shared by all subclasses.
    public String getName() {
        return this.name;
    }

    // An abstract method: it has no body. Subclasses MUST provide an implementation.
    public abstract void runMechanism(); 
}

// 2. A Concrete Subclass
public class Intake extends Mechanism {
    public Intake() {
        super("Intake"); // Call the parent constructor
    }

    // We MUST implement the abstract method from Mechanism.
    @Override
    public void runMechanism() {
        System.out.println("Intake rollers are spinning.");
    }
}
    

Interfaces: A Pure Contract

An interface is a pure blueprint of behaviors. It defines a set of methods that a class must implement, but it provides no implementation for them. An interface defines a "can-do" relationship.

When to Use an Interface

Use an interface when you want to define a capability that can be shared by unrelated classes. For example, a `Drivetrain`, a `Shooter`, and a `Limelight` are all very different, but they all can be logged to the dashboard. An interface is also how Java achieves a form of multiple inheritance.

// 1. The Interface: A contract for what a class MUST do.
public interface Loggable {
    // Any class that implements Loggable MUST have this method.
    void logToDashboard(); 
}

// 2. An Implementing Class
// A Drivetrain is not a Loggable, but it CAN BE Loggable.
public class Drivetrain extends SubsystemBase implements Loggable {
    // ... other drivetrain code ...

    @Override
    public void logToDashboard() {
        SmartDashboard.putNumber("Drivetrain Speed", getCurrentSpeed());
    }
}

// 3. Another Implementing Class
public class Shooter extends SubsystemBase implements Loggable {
    // ... other shooter code ...

    @Override
    public void logToDashboard() {
        SmartDashboard.putNumber("Shooter RPM", getRPM());
    }
}
    

Test Your Knowledge

Question: Your robot has a `Drivetrain` and an `Arm`, which are very different mechanisms. You want to ensure both have a `resetSensors()` method. What is the best OOP tool for this?