| Lesson 5 | Factory Method: motivation |
| Objective | Write an abstract Vehicle Class |
In object-oriented design, you often want to write code that works with a general concept
(like a Vehicle) without hard-coding which specific kind of vehicle you will use
(like Car, Bus, or Bicycle). This is the practical value of
polymorphism: client code can depend on a common interface while concrete subclasses
provide different behavior.
For example, an abstract base class called Vehicle may have multiple subclasses such as
Car, Bicycle, or Bus. Each subclass behaves differently
(a Bus accelerates differently than a Car), but they all support the same
public interface. That interface might include methods such as start(), stop(),
and accelerate().
Because the client only depends on the Vehicle abstraction, the same client code can work
with many different vehicle types. This is a major reason OOP systems remain extensible: you can add a
new Motorcycle or Scooter subclass later without rewriting the client logic.
Polymorphism protects your code from needing to know the exact type of an object during normal use. However, there is one moment when type knowledge tends to leak through abstraction: object creation.
In Java and C++, constructors are tightly coupled to concrete class names. When you write:
Vehicle v = new Car();
the client must know at compile time that it is creating a Car. That direct dependency is
often fine in small programs, but in frameworks, libraries, or large applications it leads to:
Creational patterns address this problem by moving creation decisions to a dedicated location and exposing
a stable API to clients. In this lesson, the key idea is: clients should rely on the abstract type
(Vehicle) and allow a factory to decide which concrete subclass to instantiate.
The Factory Method pattern defines an interface (or overridable method) for creating objects, but lets subclasses decide which concrete class to instantiate. The pattern is especially useful when:
Modern Java ecosystems often solve similar problems with dependency injection (DI) containers, service loaders, or provider-based APIs. But the underlying concept remains the same: separate object construction from object use. Factories are a classic way to do that when you want the solution to be explicit, understandable, and framework-free.
A common place where factories are needed is in frameworks that must create user-defined objects. Imagine a document
framework for multiwindow editors. You might define an abstract Document class, and users of the framework
could derive classes like TextDocument or HtmlDocument. Meanwhile, a framework component such as
DocumentManager maintains a list of open documents.
If your framework rule is “every created document must be registered with the manager,” then creation and registration should happen together in one operation. That is where Factory Method fits naturally:
class DocumentManager
{
public:
Document* NewDocument();
private:
virtual Document* CreateDocument() = 0;
std::list<Document*> listOfDocs_;
};
Document* DocumentManager::NewDocument()
{
Document* pDoc = CreateDocument();
listOfDocs_.push_back(pDoc);
...
return pDoc;
}
Notice what changed: NewDocument() does not call new directly because the framework cannot
predict the concrete document type. Instead, it calls CreateDocument(), a factory method. Subclasses override
CreateDocument() and provide the concrete instantiation:
Document* GraphicDocumentManager::CreateDocument()
{
return new GraphicDocument;
}
This structure keeps the framework code operating on the abstraction (Document) while pushing concrete type
knowledge into extension points where it belongs.
Your lesson objective is to write an abstract Vehicle class. That abstraction is the foundation
that makes Factory Method possible. If client code depends on a stable Vehicle API, then your application can
create different vehicles without rewriting the code that uses them.
In a typical design, you would:
VehicleCar, SUV, Truck, etc.Vehicle while hiding which subclass is createdThat is the “motivation” for Factory Method: it preserves abstraction even at creation time.
While Factory Method typically creates one “product” at a time, Abstract Factory creates
families of related products. The code below demonstrates a “vehicle family” factory that can
produce a Car and an SUV in a consistent style (Luxury vs Non-Luxury).
This example is useful because it shows how factories scale beyond a single creation call and become a way to manage product consistency across a system.
public abstract class VehicleFactory {
public static final String LUXURY_VEHICLE = "Luxury";
public static final String NON_LUXURY_VEHICLE = "Non-Luxury";
public abstract Car getCar();
public abstract SUV getSUV();
}
public class LuxuryVehicleFactory extends VehicleFactory {
public Car getCar() {
return new LuxuryCar("L-C");
}
public SUV getSUV() {
return new LuxurySUV("L-S");
}
}
public class NonLuxuryVehicleFactory extends VehicleFactory {
public Car getCar() {
return new NonLuxuryCar("NL-C");
}
public SUV getSUV() {
return new NonLuxurySUV("NL-S");
}
}
Even though this is labeled as “Factory Method: motivation,” this factory-family example also helps you
understand the next step: once the abstract base type exists (Vehicle), factories become a clean way
to produce objects consistently, without making client code depend on concrete classes.