Skip to main content
CleanCodeMastery

Factory Method Pattern: Let the Branch Decide the Vehicle

Learn the Factory Method design pattern with a simple Indian tiffin service story, easy TypeScript and C# code, diagrams, real examples, and practice.

25 min read Updated June 11, 2026beginner
factory methoddesign patternscreationaltypescriptoopvirtual constructor

๐ŸŽฏ The story of Sharma Aunty's tiffin service

Let us start with a small story from Pune.

Sharma Aunty runs a tiffin service called Annapoorna Tiffins. Every morning, before the sun is fully up, her kitchen is already noisy. She cooks dal, sabzi, rotis, and rice. Her two helpers, Pinky and Mohan, pack the hot food into steel dabbas. Then one delivery boy, Raju, takes the dabbas on his cycle and delivers them to offices and hostels nearby. In the evening, Raju collects the empty dabbas back, and Aunty ticks off each customer's name in her old red notebook.

The daily routine is always the same, like a fixed school timetable:

  1. Cook the food.
  2. Pack the dabbas.
  3. Load them on the vehicle.
  4. Deliver to customers.
  5. Collect empty dabbas.

Business grows. Aunty opens a second branch near the highway and puts her nephew Salim in charge. Customers there live far away, so Raju's cycle trick will not work. The highway branch uses a bike. Then a big IT park orders 200 tiffins daily. No bike can carry that. The third branch, run by Aunty's daughter Kavita, needs a van.

One evening, all three sit together for chai. Aunty asks, "Did our routine change?" Everyone shakes their head. Cooking, packing, delivering, collecting โ€” every branch follows the same five steps. Only one step changed: which vehicle to use. Each branch decides its own vehicle, but the head office never rewrites the routine.

Figure 1: One day at Annapoorna Tiffins โ€” same routine in every branch, only the vehicle step differs

This is exactly the idea behind the Factory Method pattern. The main plan stays the same. One small "create the thing" step is left open, and each branch fills it in its own way. Keep this tiffin story in your mind โ€” we will return to Aunty, Raju, Salim, and Kavita in every section of this post, and we will write the full code for their shop very soon.

๐Ÿ’ก What is the Factory Method pattern?

The Factory Method is a creational design pattern. Creational patterns are patterns about how objects are created.

Here is the plain definition. Normally, when we need an object, we write new Cycle() directly. The Factory Method pattern says: do not call new directly inside your main logic. Instead, call a special method, like createVehicle(). The base class only declares this method. The child classes (subclasses) override it and decide which exact object to return.

So the base class works only with a general type, like DeliveryVehicle. It never knows whether it will get a cycle, a bike, or a van. It simply trusts that whatever comes back can deliver tiffins. In our story, Sharma Aunty's head-office routine never says the word "cycle". It only says "the vehicle". Raju's branch quietly fills in that blank with a cycle, Salim's with a bike, Kavita's with a van.

This pattern comes from the famous 1994 book Design Patterns: Elements of Reusable Object-Oriented Software, written by four authors who are lovingly called the Gang of Four (GoF). They also gave it a second name: the Virtual Constructor, because the creation method behaves like a constructor that subclasses can change.

Figure 2: The whole Factory Method idea on one mind map
๐Ÿ’ก

One-line summary: Factory Method = the parent class writes the plan, but lets each child class decide which object to create for the plan. In tiffin language: Aunty writes the timetable; each branch picks its own vehicle.

Two roles are very important here. Please remember these names:

RoleMeaningIn our story
CreatorThe class that holds the factory method and the business logicThe tiffin branch with its daily routine
Concrete CreatorA subclass that overrides the factory methodRaju's lane branch, Salim's highway branch, Kavita's IT-park branch
ProductThe general type the factory method returnsThe idea of a "delivery vehicle"
Concrete ProductAn actual class that implements the productCycle, Bike, Van

College corner: the "Virtual Constructor" nickname is precise. Constructors in most OOP languages cannot be virtual โ€” new Cycle() is always resolved at compile time. The factory method restores late binding to creation: the call this.createVehicle() is dispatched at runtime through the vtable, so the creating line is polymorphic, just like any other virtual method. That is the entire mechanical trick behind the pattern.

โš ๏ธ The problem it solves

Let us first feel the pain. Suppose Aunty hires a part-time programmer who writes Annapoorna Tiffins without any pattern. The programmer puts an if-else chain right inside the delivery routine:

// BAD CODE: the routine and the vehicle choice are mixed together
class TiffinService {
  runDeliveryDay(branchType: string, orders: number): void {
    console.log("Cooking and packing " + orders + " tiffins...");
 
    if (branchType === "lane") {
      console.log("Loading 10 tiffins at a time on the cycle");
      console.log("Pedalling slowly through the lanes...");
    } else if (branchType === "highway") {
      console.log("Loading 30 tiffins on the bike");
      console.log("Riding fast on the highway...");
    } else if (branchType === "itpark") {
      console.log("Loading 200 tiffins in the van");
      console.log("Driving to the IT park...");
    }
 
    console.log("Collecting empty dabbas in the evening.");
  }
}

It works today. Aunty is happy for one month. But look at the troubles waiting for her tomorrow:

  • Every new branch breaks open old code. When Aunty starts a fourth branch with an e-rickshaw, the programmer must edit this working, tested method and add one more else if. Each edit can introduce new bugs in old behaviour. Kavita's van deliveries might break because someone was adding e-rickshaw code.
  • The same if-else spreads everywhere. Loading needs a branch check. Fuel cost calculation needs a branch check. Trip counting needs a branch check. Soon the same chain is copied in ten places, and one day someone updates nine of them and forgets the tenth. That tenth place is where the bug hides.
  • The routine and the vehicle details are glued together. The delivery plan should only say "use the vehicle". It should not know how a cycle is pedalled or how a van is fuelled. Aunty does not care; why should her timetable?
Figure 3: Without the pattern, every part of the code must ask the same branch question again and again

See how the new e-rickshaw branch forces us to touch three different places? In a real project, it could be thirty places. And experience across many codebases shows that creation code is exactly where a big share of avoidable bugs sit, because it is duplicated and edited so often.

Figure 4: In a typical growing codebase, scattered creation code becomes a major bug nest

Software engineers call this trap a violation of the Open/Closed Principle, which says: code should be open for extension but closed for modification. We want to add new things by writing new code, not by editing old code. Aunty already follows this rule without knowing it โ€” when she opens a new branch, she does not redesign the kitchen; she just appoints a new branch in-charge.

College corner: the deeper principle at work is the Dependency Inversion Principle (the D in SOLID). High-level policy (the delivery routine) should not depend on low-level details (Cycle, Van); both should depend on an abstraction (DeliveryVehicle). The factory method is one of the cheapest ways to invert that dependency without bringing in a full dependency-injection container.

๐Ÿ› ๏ธ How Factory Method works, step by step

Now let us fix the mess slowly, the way Aunty would โ€” one sensible decision at a time.

  1. Make all products follow one common interface. Cycle, bike, and van are all "delivery vehicles". So we create an interface DeliveryVehicle with the methods every vehicle must have, such as deliverTiffins(). In the shop, this is Aunty saying: "I do not care what it is, but it must carry dabbas and come back in the evening."
  2. Create a Creator class with an abstract factory method. We make a base class TiffinBranch. It has one special method, createVehicle(), which returns a DeliveryVehicle. The base class does not implement it โ€” it only declares it. This is the blank line in Aunty's timetable.
  3. Write the business logic using only the abstract product. The daily routine runDeliveryDay() lives in the base class. It calls this.createVehicle() and then uses the result purely as a DeliveryVehicle. It never mentions cycle, bike, or van by name.
  4. Make one subclass per variation. LaneBranch (Raju) overrides createVehicle() to return a Cycle. HighwayBranch (Salim) returns a Bike. ItParkBranch (Kavita) returns a Van.
  5. Choose the concrete creator in exactly one place. Only the starting point of the program (sometimes called the composition root) decides which branch object to make. Everything after that point is blind to the concrete classes โ€” just like Aunty's customers, who only know that hot tiffins arrive.
Figure 5: The four participants of the Factory Method pattern, drawn for our tiffin story

Look carefully at the arrows. The base class TiffinBranch points only to the interface DeliveryVehicle. The concrete creations happen only in the small subclasses at the bottom. That is the whole trick. The fancy name for what you are seeing is two parallel hierarchies: a creator hierarchy on the left, a product hierarchy on the right, joined only at the abstract level.

And here is the same idea as a conversation in time. Watch how the routine asks its own subclass for a vehicle, receives it, and then uses it blindly:

Figure 6: One delivery day as a sequence โ€” the routine asks the subclass for a vehicle, then uses it blindly
โ„น๏ธ

The factory method is often just one small step inside a bigger routine. The creator's main job is usually the routine itself; the factory method exists only so that subclasses can swap what gets created. Aunty's timetable is the star; the vehicle line is one humble blank in it.

๐Ÿงช Real-life code example

Now let us build Annapoorna Tiffins properly in TypeScript. Read it slowly, section by section. Every line has a purpose.

Section 1: the Product. First, the common interface and the three vehicles.

// ---------- PRODUCT ----------
// Every vehicle must promise these things.
interface DeliveryVehicle {
  name: string;
  capacity: number; // how many tiffins fit in one trip
  deliverTiffins(count: number): void;
}
 
// ---------- CONCRETE PRODUCTS ----------
class Cycle implements DeliveryVehicle {
  name = "cycle";
  capacity = 10;
  deliverTiffins(count: number): void {
    console.log(`  Raju pedals through the lanes with ${count} tiffins.`);
  }
}
 
class Bike implements DeliveryVehicle {
  name = "bike";
  capacity = 30;
  deliverTiffins(count: number): void {
    console.log(`  Salim rides on the highway with ${count} tiffins.`);
  }
}
 
class Van implements DeliveryVehicle {
  name = "van";
  capacity = 200;
  deliverTiffins(count: number): void {
    console.log(`  Kavita drives the van to the IT park with ${count} tiffins.`);
  }
}

Nothing fancy yet. Three classes, one shared shape. Notice that each vehicle knows its own details โ€” its capacity and its own style of delivering. The branch never needs to know these details, the same way Aunty never needs to know how much air is in Raju's cycle tyres.

Section 2: the Creator. This is the heart of the pattern.

// ---------- CREATOR ----------
abstract class TiffinBranch {
  constructor(public branchName: string) {}
 
  // THE FACTORY METHOD.
  // The base class declares it but does not implement it.
  protected abstract createVehicle(): DeliveryVehicle;
 
  // The daily routine: same for EVERY branch.
  // It talks only to the DeliveryVehicle interface.
  runDeliveryDay(orders: number): void {
    console.log(`--- ${this.branchName}: delivery day starts ---`);
    console.log(`Cooking and packing ${orders} tiffins...`);
 
    const vehicle = this.createVehicle(); // <-- the magic line
 
    let remaining = orders;
    let trip = 1;
    while (remaining > 0) {
      const load = Math.min(vehicle.capacity, remaining);
      console.log(`Trip ${trip}: loading ${load} tiffins on the ${vehicle.name}.`);
      vehicle.deliverTiffins(load);
      remaining -= load;
      trip++;
    }
 
    console.log(`All ${orders} tiffins delivered. Empty dabbas tomorrow!`);
  }
}

Please notice three things here:

  • createVehicle() is abstract. The base class is honestly saying: "I do not know which vehicle. My children will tell."
  • runDeliveryDay() is full, complete business logic. It loads trips, counts them, and prints messages. But it never writes new Cycle() or checks if (branch === "lane"). There is zero branching on type.
  • The variable vehicle has the type DeliveryVehicle. The routine works the same whether 10 fit per trip or 200 fit per trip, because it reads vehicle.capacity instead of hard-coding a number.

Section 3: the Concrete Creators. Each branch is tiny. It overrides just one method.

// ---------- CONCRETE CREATORS ----------
class LaneBranch extends TiffinBranch {
  protected createVehicle(): DeliveryVehicle {
    return new Cycle();
  }
}
 
class HighwayBranch extends TiffinBranch {
  protected createVehicle(): DeliveryVehicle {
    return new Bike();
  }
}
 
class ItParkBranch extends TiffinBranch {
  protected createVehicle(): DeliveryVehicle {
    return new Van();
  }
}

Section 4: the client code. Only this one spot knows the concrete classes.

// ---------- CLIENT ----------
const branches: TiffinBranch[] = [
  new LaneBranch("Annapoorna - Old City Lane"),
  new HighwayBranch("Annapoorna - Highway"),
  new ItParkBranch("Annapoorna - IT Park"),
];
 
for (const branch of branches) {
  branch.runDeliveryDay(35);
}

Run it, and you will see the same routine produce three different behaviours โ€” and not a single if-else about vehicle types anywhere in the routine. Raju makes four cycle trips for 35 tiffins, Salim makes two bike trips, and Kavita finishes the whole job in one van trip.

Now the best part of the whole story. Aunty buys an e-rickshaw for a new market branch and gives it to her neighbour Babita. What do we change in the existing code? Nothing. We only add:

class ERickshaw implements DeliveryVehicle {
  name = "e-rickshaw";
  capacity = 50;
  deliverTiffins(count: number): void {
    console.log(`  Babita glides silently with ${count} tiffins.`);
  }
}
 
class MarketBranch extends TiffinBranch {
  protected createVehicle(): DeliveryVehicle {
    return new ERickshaw();
  }
}

Old code untouched. Old tests still green. Raju, Salim, and Kavita never even noticed. That is the Open/Closed Principle working for us.

College corner: this "add, don't edit" property is also a testing superpower. Because createVehicle() is an overridable seam, a unit test can subclass TiffinBranch with a FakeBranch whose factory method returns a MockVehicle that records calls. You can then assert the routine's trip-splitting logic without any real vehicle, console, or I/O. Factory methods are one of the classic "seams" described in Working Effectively with Legacy Code.

๐Ÿ“Š The same idea in C#

The pattern looks almost identical in C#. Here is a shorter version, so you can see that the idea is language-independent:

// Product
public interface IDeliveryVehicle
{
    string Name { get; }
    int Capacity { get; }
    void DeliverTiffins(int count);
}
 
public class Cycle : IDeliveryVehicle
{
    public string Name => "cycle";
    public int Capacity => 10;
    public void DeliverTiffins(int count) =>
        Console.WriteLine($"  Pedalling with {count} tiffins.");
}
 
public class Van : IDeliveryVehicle
{
    public string Name => "van";
    public int Capacity => 200;
    public void DeliverTiffins(int count) =>
        Console.WriteLine($"  Driving with {count} tiffins.");
}
 
// Creator
public abstract class TiffinBranch
{
    // The factory method
    protected abstract IDeliveryVehicle CreateVehicle();
 
    public void RunDeliveryDay(int orders)
    {
        var vehicle = CreateVehicle();
        for (int left = orders; left > 0; left -= vehicle.Capacity)
        {
            vehicle.DeliverTiffins(Math.Min(vehicle.Capacity, left));
        }
        Console.WriteLine($"All {orders} tiffins delivered.");
    }
}
 
// Concrete creators
public class LaneBranch : TiffinBranch
{
    protected override IDeliveryVehicle CreateVehicle() => new Cycle();
}
 
public class ItParkBranch : TiffinBranch
{
    protected override IDeliveryVehicle CreateVehicle() => new Van();
}

The shape is the same: abstract method in the parent, override in the children, business logic in the parent that never names a concrete class.

And here is a small Python variation that many real projects use โ€” a factory method with a default implementation instead of an abstract one. The base branch returns a cycle by default, and only branches that need something different override it:

class TiffinBranch:
    def create_vehicle(self):
        # Default factory method: most branches start with a cycle.
        return Cycle()
 
    def run_delivery_day(self, orders: int) -> None:
        vehicle = self.create_vehicle()
        left = orders
        while left > 0:
            load = min(vehicle.capacity, left)
            vehicle.deliver_tiffins(load)
            left -= load
 
 
class ItParkBranch(TiffinBranch):
    def create_vehicle(self):
        return Van()   # only this branch overrides the default

This "default product" variation is handy when one product covers 80 percent of cases. New branches get sensible behaviour for free and override only when they truly differ โ€” exactly how Aunty hands every new branch a cycle on day one and upgrades later.

๐Ÿ’ก Where you see it in real software

This is not just a classroom idea. Famous libraries and frameworks use Factory Method every single day.

  • .NET's ILoggerFactory. When a .NET program needs a logger, it does not write new ConsoleLogger(). It asks the factory: loggerFactory.CreateLogger("MyApp"). The factory decides whether the logger writes to the console, a file, or a cloud service. Your code only sees the ILogger interface โ€” exactly like our branch only sees DeliveryVehicle.
  • Java's Calendar.getInstance() and NumberFormat.getInstance(). You ask for "a calendar" or "a number format", and Java returns the correct concrete class for your locale and settings. You never name the concrete class yourself.
  • SLF4J's LoggerFactory.getLogger() in the Java world works the same way: the call site stays fixed while the actual logger implementation can be swapped underneath.
  • ADO.NET's DbCommand creation. Database code asks a connection to create a command, and the right concrete command for SQL Server, MySQL, or Oracle comes back.
  • GUI frameworks use factory methods so the framework can call "create a button" and your subclass can supply a custom button, without forking the framework. The framework is Aunty's timetable; your subclass is the branch.

If you want to read real, well-organized implementations, two GitHub repositories are excellent for students: iluwatar/java-design-patterns (Java, with diagrams and explanations for every pattern) and faif/python-patterns (short, readable Python versions). The page on Refactoring Guru is also a friendly read with pictures.

๐ŸŽฏ When to use it and when not to

A pattern is a tool, not a rule. First, locate your project on this map. Annapoorna Tiffins sits in the top-right corner: it already has several vehicle types and clearly keeps adding more.

Figure 7: Should your project use Factory Method? Find your spot on the map

Then confirm with this table:

SituationUse Factory Method?Why
You will surely need more product types later (more vehicles, more loggers)โœ… YesNew types become new subclasses; old code stays safe
You are writing a framework or library others will extendโœ… YesUsers override the factory method to plug in their own products
Object creation has extra logic (caching, pooling, validation)โœ… YesThe factory method gives that logic one named home
The creator hierarchy already exists for other reasonsโœ… YesThe pattern fits in almost for free
There is exactly one product type, and it will never changeโŒ NoA plain new is shorter and clearer
You only need one small creation function with no shared routineโŒ NoA simple factory function is enough; no inheritance needed
You need to create a whole family of matching objectsโŒ NoThat job belongs to Abstract Factory, the bigger cousin

And what does the pattern actually buy you when a new type arrives? Think of the day Babita's e-rickshaw branch opened. Without the pattern, the programmer hunts through every if-else in the project. With the pattern, it is one new product class and one tiny subclass:

Figure 8: The payoff โ€” code touched when Aunty adds the e-rickshaw branch

Zero edited lines is not an exaggeration โ€” it is the whole point. The new behaviour arrives purely as new files.

College corner: the honest cost side: Factory Method creates a parallel class hierarchy โ€” one creator subclass per product. If you have 15 products, you may carry 15 nearly empty creator classes. In languages with first-class functions, teams often replace the hierarchy with an injected creation function (for example, a () => DeliveryVehicle lambda passed into the constructor). That is the same pattern, expressed with composition instead of inheritance, and it is usually preferred in modern TypeScript.

๐Ÿ› ๏ธ Lifecycle of one tiffin order

It also helps to see the life of a single order as states. Notice where the factory method fires: exactly once, between accepting the order and loading the vehicle.

Figure 9: The life of one delivery order โ€” the factory method runs at the VehicleReady transition

Every state before and after VehicleReady is identical for all branches. The pattern isolates exactly one transition and lets it vary. When you design your own factory methods, draw this kind of diagram and ask: which single transition actually differs between my variants? If the answer is "many transitions", you may need a different pattern (perhaps Template Method with several hooks, or Strategy objects).

๐Ÿ“Š Compare with cousins

Factory Method has famous relatives in the creational family. Here is how to tell them apart:

PatternCreatesMain question it answersShape
Factory MethodOne product"Which one object should this step create?"One overridable method in a creator hierarchy
Abstract FactoryA family of products"Which matching set of objects do I need?"One interface with many create methods
BuilderOne complex product"How do I assemble this big object step by step?"Chained step methods ending in build()
PrototypeA copy of a product"Can I clone an existing object instead of building new?"A clone() method
Simple factory (idiom)One product"Can one function with a switch pick the class?"A single static function (not a GoF pattern)

In tiffin language: Factory Method picks the vehicle. Abstract Factory (next post โ€” Meena Tai's catering!) hands out a whole matching thali set. Builder stitches one complicated kurta step by step. Prototype photocopies an existing order.

A small extra note: Factory Method is really a special case of the Template Method pattern. The routine runDeliveryDay() is a template โ€” a fixed skeleton โ€” and createVehicle() is the one step the children customize. Many designs also start with a Factory Method because it is simple, and later grow into Abstract Factory when more related products appear.

โš ๏ธ Common mistakes students make

โš ๏ธ

Mistake 1: Putting if-else back inside the factory method. Some students write one createVehicle(type) with a big switch inside the base class. That is a "simple factory", not the Factory Method pattern โ€” and the switch must be edited for every new type. It is like Aunty herself running to every branch each morning to pick the vehicle. If you have many types, prefer one subclass per type.

โš ๏ธ

Mistake 2: Letting the routine peek at concrete types. Writing if (vehicle instanceof Van) inside runDeliveryDay() destroys the whole benefit. The routine must stay blind. If you feel the need to check the type, the missing behaviour probably belongs inside the product classes.

โš ๏ธ

Mistake 3: Creating factories for everything. A factory for a simple Student object with two fields is over-engineering. Patterns solve pain. No pain, no pattern.

๐Ÿšจ

Mistake 4: Forgetting the single configuration point. The concrete creator should be chosen in one place (the program's entry point or config). If you scatter new LaneBranch() calls all over the app, you have just moved the coupling problem to a new address.

Here is the same list as a quick-scan table for revision time:

MistakeWhat it looks likeThe fix
Switch inside the factory methodcreateVehicle(type) with a big switchOne concrete creator per type
Routine peeks at typesinstanceof Van checks in the routineMove the behaviour into the product class
Pattern everywhereFactories for two-field objectsUse a plain constructor until it hurts
Scattered concrete creatorsnew LaneBranch() in twenty filesOne composition root chooses the creator

๐Ÿงช Quick revision box

+===============================================================+
|              FACTORY METHOD - QUICK REVISION                  |
+===============================================================+
|  IDEA      : Parent declares createX(); children decide      |
|              which concrete object to return.                |
|  ALSO CALLED: Virtual Constructor (GoF, 1994)                 |
|---------------------------------------------------------------|
|  PARTICIPANTS                                                 |
|    Product          -> DeliveryVehicle (interface)            |
|    ConcreteProduct  -> Cycle, Bike, Van                       |
|    Creator          -> TiffinBranch (has routine + factory)   |
|    ConcreteCreator  -> LaneBranch, HighwayBranch, ItParkBranch|
|---------------------------------------------------------------|
|  GOLDEN RULES                                                 |
|    1. Routine talks ONLY to the abstract product.             |
|    2. New type = new subclass, NOT new if-else.               |
|    3. Pick the concrete creator in ONE place only.            |
|---------------------------------------------------------------|
|  REAL LIFE  : ILoggerFactory (.NET), Calendar.getInstance(),  |
|               SLF4J LoggerFactory.getLogger()                 |
|  REMEMBER   : "Same tiffin routine, different vehicle."       |
+===============================================================+

๐ŸŽฏ Practice exercise

Time to cook your own code! Try these tasks:

  1. Add a drone branch. Annapoorna Tiffins is testing drone delivery for a hill-top hostel. Create a Drone product (capacity 2, very fast) and a HillBranch creator. Confirm that you did not edit even one old line.
  2. Notification factory. A school app sends exam reminders. Build a Notifier interface with send(message), products SmsNotifier, EmailNotifier, and WhatsAppNotifier, and a creator ReminderService whose routine formats the message, calls the factory method, and sends. Make one subclass per channel.
  3. Draw before you code. For exercise 2, draw your own versions of Figure 5 (class diagram) and Figure 9 (state diagram). Mark the exact transition where your factory method fires.
  4. Think and write (no code). Your friend says, "I will just write one function makeVehicle(type: string) with a switch โ€” why all these classes?" Write 4-5 sentences explaining when your friend's simple factory is fine, and when the full Factory Method pattern is the better choice.
  5. College corner challenge. Replace the creator hierarchy with composition: give TiffinBranch a constructor parameter of type () => DeliveryVehicle and delete all three subclasses. Compare both designs โ€” which one would you ship, and why?

Well done for reading till here. Sharma Aunty's shop taught you the smallest, friendliest factory. Next, meet the bigger cousin: the Abstract Factory pattern, where Meena Tai's wedding kitchen creates whole families of matching objects.

Frequently asked questions

What is the Factory Method pattern in one line?
It is a way of creating objects where the main class only asks for an object through a special method, and child classes decide which exact object to make. So the creating decision moves out of the main logic and into small, separate classes.
Is Factory Method the same as a simple factory function?
Not exactly. A simple factory is just one function with if-else inside that returns different objects. Factory Method uses inheritance: a base class declares the creation method and each subclass overrides it. The simple factory is easier, but it must be edited every time a new type comes.
Why not just use the new keyword directly?
Using new directly ties your code to one fixed class. If tomorrow you need a different class, you must open and change working code in many places. Factory Method keeps that decision in one place, so adding a new type means adding new code, not changing old code.
When is Factory Method too much?
If you create only one kind of object and that will never change, a plain constructor is enough. Adding factory classes for a single fixed type makes the code longer without giving any benefit. Use the pattern when you expect more types in future.
How is Factory Method different from Abstract Factory?
Factory Method creates one product using one overridable method. Abstract Factory is bigger: it creates a whole family of related products together, like a full matching set. In fact, an Abstract Factory is usually built out of several Factory Methods.

Further reading

Related Lessons