Creational Patterns «Prev Next»

Lesson 7Factory Method: consequences
ObjectiveWrite a class using the Factory Method Pattern

Factory Method Consequences

In the previous lessons, you built the Vehicle abstraction and then created concrete subclasses (Car, Bus, Bicycle, Pedestrian). This lesson completes the Factory Method workflow: you will write a class that creates those subclasses through an interface, so client code depends on Vehicle (the abstraction) rather than concrete class names.

What changes when you introduce a Factory Method?

Without a factory, client code typically contains explicit construction logic:

// Client code WITHOUT a factory (tight coupling)
Vehicle v = new Car();  // client is now coupled to "Car"

With a Factory Method, client code requests a Vehicle from a creator, and the creator decides which concrete subclass to instantiate:

// Client code WITH a factory (loose coupling)
Vehicle v = factory.createVehicle();

That single change has measurable consequences—both good and bad.

Advantages

Disadvantages

The key is to apply Factory Method when it buys you real flexibility: multiple concrete subclasses, runtime selection, or a desire to hide construction details from clients.

Why clients should not implement selection logic

If every client has to decide which subclass to instantiate, you usually end up with repeated conditional logic scattered throughout the codebase:

// Example problem: repeated selection logic in every client
Vehicle v;
if (config.equals("car")) v = new Car();
else if (config.equals("bus")) v = new Bus();
else v = new Bicycle();

That design has predictable weaknesses:

  1. Clients become tightly coupled to the concrete subclass hierarchy.
  2. When selection rules change, many call sites must be updated.
  3. Code becomes cluttered with conditional statements that are unrelated to the client’s main job.

Factory Method moves that responsibility to a creator class that exists specifically to manage creation policy.

Example: a VehicleFactory using a parameterized Factory Method

Because your module already defines multiple concrete Vehicle subclasses, the simplest next step is a parameterized factory. This avoids creating a separate creator class per concrete product while still returning the abstract type Vehicle.


public class VehicleFactory {

  public static final String CAR = "car";
  public static final String BUS = "bus";
  public static final String BICYCLE = "bicycle";
  public static final String PEDESTRIAN = "pedestrian";

  public Vehicle createVehicle(String type) {
    if (type == null) {
      throw new IllegalArgumentException("type must not be null");
    }

    String t = type.trim().toLowerCase();

    if (CAR.equals(t)) return new Car();
    if (BUS.equals(t)) return new Bus();
    if (BICYCLE.equals(t)) return new Bicycle();
    if (PEDESTRIAN.equals(t)) return new Pedestrian();

    throw new IllegalArgumentException("Unknown vehicle type: " + type);
  }
}

This class demonstrates the lesson objective directly: it is a dedicated creation component that returns Vehicle while selecting the correct concrete subclass internally.

Modern design note

In modern systems, you may see this same idea implemented with dependency injection containers, registries, or service loaders. Even then, the Factory Method principle remains unchanged: centralize creation policy and return abstractions.

Factory Consequences - Exercise

In this exercise, a VehicleFactory class will be created.
Factory Consequences - Exercise

SEMrush Software 7 SEMrush Banner 7