Factory
What is the Factory Pattern?
The Factory Pattern is a creational design pattern that provides a method to create objects without specifying the exact class of the object that will be created.
Instead of calling a constructor directly, you use a factory method that decides which class or object to return, often based on configuration or parameters.
Why Use Factory in FRC Robot Code?
FRC robots often support multiple hardware configurations, autonomous modes, or testing environments. Using Factory methods allows you to:
Decouple what you want from how it’s created.
Cleanly switch between real vs. simulated hardware.
Support different robot builds (e.g., comp bot vs. practice bot).
Create named commands or auto paths without hardcoding logic in multiple places.
Make subsystem mocking easier for tests.
Real-World Use Cases in FRC
Subsystem Factories
Return different drivetrain implementations depending on hardware or sim.
Autonomous Command Factories
Create Command
objects based on selected auto mode.
Input Device Factories
Return real or simulated controllers.
Sensor Factories
Choose between real or mocked sensors (encoders, gyros, cameras).
Basic Factory Example: Subsystem
Let’s build a Drivetrain Factory that can return either a real or simulated drivetrain based on some config setting.
Step 1: Define the interface/base class
public interface Drivetrain {
void drive(double speed, double turn);
}
Step 2: Implement two versions
public class RealDrivetrain implements Drivetrain {
public void drive(double speed, double turn) {
// Control Talons, Sparks, etc.
}
}
public class SimDrivetrain implements Drivetrain {
public void drive(double speed, double turn) {
// Simulate motion using WPILib simulation
}
}
Step 3: Create the factory
public class DrivetrainFactory {
public static Drivetrain createDrivetrain() {
if (RobotBase.isReal()) {
return new RealDrivetrain();
} else {
return new SimDrivetrain();
}
}
}
Step 4: Use the factory in your robot code
Drivetrain drivetrain = DrivetrainFactory.createDrivetrain();
Factory for Autonomous Commands
public class AutoFactory {
public static Command createAuto(String mode) {
return switch (mode) {
case "Taxi" -> new DriveForwardCommand(3.0);
case "2 Ball" -> new TwoBallAutoCommand();
case "Nothing" -> new WaitCommand(0.1);
default -> new PrintCommand("Unknown Auto Mode");
};
}
}
Then in RobotContainer
or wherever you choose the auto:
SendableChooser<String> chooser = new SendableChooser<>();
chooser.addOption("Taxi", "Taxi");
chooser.addOption("2 Ball", "2 Ball");
...
Command auto = AutoFactory.createAuto(chooser.getSelected());
Factory vs Builder vs Strategy
Factory
Creates an object based on logic/conditions
Real vs. simulated gyro or drivetrain
Builder
Builds complex object step-by-step
Shooter PID config, path builder
Strategy
Switch between interchangeable behaviors
Different IO classes for same subsystem
Key Benefits in FRC
Hardware abstraction: Write code once, switch implementations automatically.
Easier testing: Use mock versions of subsystems in tests.
Auto selector clarity: Cleanly generate commands from dashboard input.
Avoid duplication: Avoid repeating creation logic in multiple places.
Example: Sensor Factory
public interface Gyro {
double getHeading();
}
public class PigeonGyro implements Gyro {
private final Pigeon2 pigeon = new Pigeon2(0);
public double getHeading() {
return pigeon.getYaw();
}
}
public class SimGyro implements Gyro {
private double heading = 0;
public double getHeading() {
return heading;
}
}
public class GyroFactory {
public static Gyro createGyro() {
return RobotBase.isReal() ? new PigeonGyro() : new SimGyro();
}
}
Best Practices
Keep factory logic simple and focused.
Return interfaces when possible (not concrete classes).
Centralize decision-making (don’t duplicate "real vs sim" logic all over).
You can combine with Singleton if the factory returns shared instances.
Last updated