2Brute2Best
πŸ”₯0
A5

Creating Deliveries & Gateways Without Scattered new

High-frequency interview topic Pro OnlyFactory MethodSimple Factory std::unique_ptr
⚑ 60-Second Architecture SummaryA5 · Factory Method (+ Simple Factory)
Naive Bottleneck→Factory Method (+ Simple Factory) Cure
The Naive Bottleneck: Scattered creational coupling across the codebase

Scattering `if (mode == "BIKE") new ExpressBikePartner(...)` and direct instantiation across dispatchers, background jobs, and admin consoles tightly couples callers to concrete partner constructors and their complex private parameters (like aviation permits for drones). Changing a single constructor breaks ten different files.

Callers that only need to call dispatch(orderId) are tightly coupled to every concrete class constructor and its private initialization parameters.

The Pattern Cure: Factory Method (+ Simple Factory)

Define an interface for creating an object, but let subclasses decide which class to instantiate, deferring instantiation to specialized creators.

We define a common DeliveryPartner product interface. For simple string/enum conversion, a Simple Factory (DeliveryPartnerFactory) encapsulates parameter lookups in one place. For architectural workflows, the Factory Method pattern defines a FulfillmentService base class whose fulfillOrder() template method delegates partner creation to a pure virtual createDeliveryPartner() factory method implemented by regional creator subclasses.

Sprint 5 of 9 Β· Delivery Partner Creation & Dispatch
Story A β€” Food Delivery System β€” Progressive System Build
1. Where our codebase left off
← A4

In Sprint 4 (A4), we implemented an OrderState state machine ensuring orders transition cleanly through Placed, Accepted, Cooking, PickedUp, and Delivered.

2. What we are building now

When cooking finishes and an order transitions to pickup, our fulfillment engine must dispatch the appropriate delivery partner (ExpressBikePartner, EcoBatchPartner, or DronePartner) based on urban zones, campus restrictions, and delivery urgency.

3. The pain point we hit

Scattering if (mode == "BIKE") new ExpressBikePartner(...) and direct instantiation across dispatchers, background jobs, and admin consoles tightly couples callers to concrete partner constructors and their complex private parameters (like aviation permits for drones). Changing a single constructor breaks ten different files.

4. What this unlocks next
Next: A6 β†’

Using Factory Method (with FulfillmentService creators deferring partner creation to subclasses like UrbanExpressFulfillment and TechParkFulfillment), callers depend purely on the abstract DeliveryPartner interface. Next in Sprint 6 (A6 Β· DIP), we discover that our high-level OrderService still directly instantiates concrete database and payment clients, making unit tests slow, brittle, and network-dependent.

01

The product ticket

Ticket Β· A5FOOD-105 Β· Centralize Delivery Partner Instantiation with Factory Method

Our logistics engine assigns different delivery fleets based on order urgency, location, and packaging: ExpressBikeDelivery (urgent motorcycle couriers), EcoBatchDelivery (batched electric bikes for university campuses), and DroneDelivery (autonomous aerial drops for tech parks).

Requirements
  • β€’

    Support multiple fulfillment modes with differing pricing algorithms and dispatch mechanisms.

  • β€’

    Prevent callers throughout the app from scattering new or make_unique calls for concrete partner classes.

  • β€’

    Allow specialized regional fulfillment centers to define which partner fleet to instantiate without altering core dispatch workflows.

The next requirement that breaks naive code

Autonomous drones require security permits (flightPermit_) and airspace clearance tokens during construction. In the naive codebase, every caller initializing DroneDelivery had to copy-paste dummy permit strings and config lookups. When constructor parameters change, ten different files break simultaneously.

02

Step 1 β€” The naive code & why it breaks

Every caller (OrderDispatcher, ScheduledDeliveryJob, AdminFulfillmentConsole) directly instantiates concrete delivery classes with new or std::make_unique inside repetitive if / else chains.

Naive design (what not to ship) Β· naive.cpp
#include <memory>
#include <print>
#include <string>

// Concrete delivery partner classes:
class ExpressBikeDelivery {
public:
    void dispatch(const std::string& orderId) {
        std::println("[EXPRESS BIKE] Urgent rider dispatched for order {}", orderId);
    }
};

class EcoBatchDelivery {
public:
    void dispatch(const std::string& orderId) {
        std::println("[ECO BATCH] Batched EV courier queued for order {}", orderId);
    }
};

class DroneDelivery {
    std::string flightPermit_;
public:
    explicit DroneDelivery(std::string permit) : flightPermit_(std::move(permit)) {}
    void dispatch(const std::string& orderId) {
        std::println("[DRONE] Aerial drone dispatched for order {} (permit: {})", orderId, flightPermit_);
    }
};

// Caller 1: Normal Order Dispatcher
class OrderDispatcher {
public:
    void dispatchOrder(const std::string& orderId, const std::string& type) {
        // Scattered instantiation with hardcoded conditional logic:
        if (type == "EXPRESS") {
            auto partner = std::make_unique<ExpressBikeDelivery>();
            partner->dispatch(orderId);
        } else if (type == "ECO") {
            auto partner = std::make_unique<EcoBatchDelivery>();
            partner->dispatch(orderId);
        } else if (type == "DRONE") {
            // Caller has to know Drone needs a permit ID!
            auto partner = std::make_unique<DroneDelivery>("DGCA-BLR-404");
            partner->dispatch(orderId);
        }
    }
};

// Caller 2: Scheduled Bulk Job (duplicates the exact same construction logic!)
class ScheduledDeliveryJob {
public:
    void runJob(const std::string& orderId, const std::string& type) {
        if (type == "EXPRESS") {
            auto partner = std::make_unique<ExpressBikeDelivery>();
            partner->dispatch(orderId);
        } else if (type == "ECO") {
            auto partner = std::make_unique<EcoBatchDelivery>();
            partner->dispatch(orderId);
        } else if (type == "DRONE") {
            auto partner = std::make_unique<DroneDelivery>("DGCA-BLR-404");
            partner->dispatch(orderId);
        }
    }
};

int main() {
    OrderDispatcher dispatcher;
    dispatcher.dispatchOrder("ORD-501", "EXPRESS");
    dispatcher.dispatchOrder("ORD-502", "DRONE");

    ScheduledDeliveryJob job;
    job.runJob("ORD-503", "ECO");
}
Scattered creational coupling across the codebase

Callers that only need to call dispatch(orderId) are tightly coupled to every concrete class constructor and its private initialization parameters.

Constructor parameter changes trigger widespread breakages

When DroneDelivery adds a required aviation permit argument, developers must update every single new DroneDelivery(...) call site scattered across separate job and service files.

Duplicated type-switching conditionals

The same if (type == "EXPRESS") ... else if (type == "DRONE") logic is duplicated across multiple background jobs, violating DRY.

03

Step 2 β€” The fix: Factory Method (+ Simple Factory)

Core idea in one sentence

Define an interface for creating an object, but let subclasses decide which class to instantiate, deferring instantiation to specialized creators.

We define a common DeliveryPartner product interface. For simple string/enum conversion, a Simple Factory (DeliveryPartnerFactory) encapsulates parameter lookups in one place. For architectural workflows, the Factory Method pattern defines a FulfillmentService base class whose fulfillOrder() template method delegates partner creation to a pure virtual createDeliveryPartner() factory method implemented by regional creator subclasses.

Pattern roles in our story
Product Interface

DeliveryPartner β€” declares common methods dispatch(orderId), partnerType(), and costPaise(distance).

Concrete Products

ExpressBikePartner, EcoBatchPartner, DronePartner β€” implement dispatch logic and vehicle-specific cost calculations.

Creator (Base)

FulfillmentService β€” defines the high-level fulfillOrder() workflow and declares the createDeliveryPartner() factory method.

Concrete Creators

UrbanExpressFulfillment, GreenCampusFulfillment, TechParkFulfillment β€” override the factory method to return the right concrete partner.

Brute2Best Pro Content

Unlock Full UML Diagram & C++23 Solution

The interactive UML architecture diagrams, refactored C++23 code, real-world extensions, and interview Q&A are part of Brute2Best Pro. All 7 foundation chapters are 100% free.

All 440 visual dry runs & algorithms
Interactive step-by-step playback with pointer & array state transitions
52 comprehensive LLD chapters
Interactive UML diagrams, real-world stories (Food Delivery, Trading, RPG), and practice solutions
40 C++ basics labs & hardware memory models
Vtables, byte layouts, assembly insights, and multi-threading race conditions
Production-ready C++23 source code
Modern idioms, clean contracts, time/space complexity derivations, and interview takeaways

First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.

Systems Integration

Related C++ Systems & Algorithmic Foundations

Deep dive into underlying layers