2Brute2Best
πŸ”₯0
A8

Integrating a Partner Restaurant's Legacy API

High-frequency interview topic Pro OnlyAdapter
⚑ 60-Second Architecture SummaryA8 · Adapter (Object Adapter)
Naive Bottleneck→Adapter (Object Adapter) Cure
The Naive Bottleneck: OrderService violates the Open-Closed Principle (OCP)

External vendor SDKs have completely incompatible APIs: `LegacyPizzaSdk` expects raw C-strings (`const char*`), item SKU maps, and integer paise (`int64_t`), while third-party payment SDKs (`StripeIndiaSDK`) don't match our Sprint 1 `PaymentStrategy` interface. Scattering `if (isLegacy)` conditionals, paise arithmetic, and string parsing inside `OrderService` or `Checkout` violates OCP and pollutes core business logic.

Every time an external restaurant with an idiosyncratic POS SDK joins our platform, OrderService must be modified with new branching logic and conversion math.

The Pattern Cure: Adapter (Object Adapter)

Convert the interface of an existing class into another interface that clients expect, allowing classes with incompatible interfaces to collaborate.

We create LegacyPizzaAdapter which implements our standard RestaurantPartner interface and wraps an instance of LegacyPizzaSdk. When placeOrder(order) is called on the adapter, it translates rupee doubles into integer paise, maps item names to legacy SKU codes, and delegates to submitLegacyTicket(). OrderService talks only to RestaurantPartner.

Sprint 8 of 9 Β· Integrating Incompatible 3rd-Party Gateways & Partner SDKs
Story A β€” Food Delivery System β€” Progressive System Build
1. Where our codebase left off
← A7

In Sprint 7 (A7), we segregated partner and payment contracts into lean role interfaces (DeliveryPartner, Payable, OnlineRefundable), ensuring our system speaks clean C++ domain structs with rupee values.

2. What we are building now

We need to onboard external restaurant chains (like Bella Pizza) and third-party payment gateways (like StripeIndiaSDK) to expand our merchant catalog and payment options.

3. The pain point we hit

External vendor SDKs have completely incompatible APIs: LegacyPizzaSdk expects raw C-strings (const char*), item SKU maps, and integer paise (int64_t), while third-party payment SDKs (StripeIndiaSDK) don't match our Sprint 1 PaymentStrategy interface. Scattering if (isLegacy) conditionals, paise arithmetic, and string parsing inside OrderService or Checkout violates OCP and pollutes core business logic.

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

By wrapping third-party SDKs inside an Adapter (LegacyPizzaAdapter / StripePaymentAdapter), incompatible vendor APIs plug directly into our RestaurantPartner and PaymentStrategy interfaces without touching existing checkout code. Next in Sprint 9 (A9 Β· Facade), the mobile app team complains that placing an order requires coordinating six subsystems (CartValidator, TaxCalculator, PaymentStrategy, Inventory, DeliveryDispatcher, OrderSubject) in exact sequence.

01

The product ticket

Ticket Β· A8FOOD-108 Β· Integrate Legacy National Pizza Chain SDK

We signed an agreement to onboard Bella Pizza, a nationwide restaurant franchise. However, their internal ordering system relies on a decade-old legacy SDK (LegacyPizzaSdk). It expects item codes as raw C-strings ("PZ_PEP_02"), prices in integer paise (1 Rupee = 100 Paise), and phone numbers as const char*, invoking submitLegacyTicket(). This is completely incompatible with our modern RestaurantPartner interface which accepts OrderRequest structs with prices in rupees.

Requirements
  • β€’

    Integrate Bella Pizza without modifying their proprietary third-party SDK (we do not own the SDK source code).

  • β€’

    Do NOT add vendor-specific if/else checks, paise conversions, or item-code maps inside OrderService.

  • β€’

    Ensure OrderService interacts with Bella Pizza seamlessly via our standard RestaurantPartner interface.

The next requirement that breaks naive code

Next quarter, two more national chains (Burger King and Subway) will integrate their own legacy POS SDKs with custom binary payload formats. The core order dispatch engine must stay completely untouched.

02

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

The initial instinct is to add an if (isLegacyPizzaPartner) branch directly inside OrderService, manually converting rupees to paise and item names to legacy SKU strings.

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

struct OrderRequest {
    std::string orderId;
    std::string customerPhone;
    std::string itemName;
    double priceRupees;
};

struct OrderResponse {
    bool success;
    std::string confirmationId;
    std::string message;
};

// Target interface standard in our modern platform
class RestaurantPartner {
public:
    virtual ~RestaurantPartner() = default;
    virtual OrderResponse placeOrder(const OrderRequest& order) = 0;
};

class StandardRestaurantPartner : public RestaurantPartner {
public:
    OrderResponse placeOrder(const OrderRequest& order) override {
        std::println("[StandardPartner] Accepted order {} for {} (Rs.{:.2f})",
                     order.orderId, order.itemName, order.priceRupees);
        return {true, std::format("CONF_{}", order.orderId), "Order accepted"};
    }
};

// Legacy 3rd-party vendor SDK (we do NOT own or modify this class!)
struct LegacyTicketResult {
    int statusCode; // 0 = SUCCESS, 1 = INVALID_ITEM, 2 = NETWORK_ERROR
    std::string legacyTicketRef;
};

class LegacyPizzaSdk {
public:
    LegacyTicketResult submitLegacyTicket(const char* itemCode, int64_t amountPaise, const char* phoneStr) {
        std::println("[LegacyPizzaSdk] Submitting legacy ticket: code='{}', amountPaise={}, phone='{}'",
                     itemCode, amountPaise, phoneStr);
        if (std::string_view(itemCode) == "UNKNOWN") {
            return {1, ""};
        }
        return {0, std::format("LEGACY_TKT_{}", amountPaise % 10000)};
    }
};

// Naive OrderService: mixes legacy vendor branching and unit conversions directly in business logic!
class NaiveOrderService {
    std::shared_ptr<RestaurantPartner> standardPartner_;
    LegacyPizzaSdk legacySdk_;
public:
    explicit NaiveOrderService(std::shared_ptr<RestaurantPartner> partner)
        : standardPartner_(std::move(partner)), legacySdk_() {}

    OrderResponse dispatchOrder(const OrderRequest& req, bool isLegacyPizzaPartner) {
        std::println("--- Dispatching Order {} ---", req.orderId);
        if (isLegacyPizzaPartner) {
            // Naive code smell: translating vendor formats directly inside core service!
            int64_t paise = static_cast<int64_t>(req.priceRupees * 100.0 + 0.5);
            std::string code = (req.itemName == "Margherita") ? "PZ_MARG_01" :
                               (req.itemName == "Pepperoni")  ? "PZ_PEP_02" : "UNKNOWN";

            auto legacyRes = legacySdk_.submitLegacyTicket(code.c_str(), paise, req.customerPhone.c_str());
            if (legacyRes.statusCode == 0) {
                return {true, legacyRes.legacyTicketRef, "Legacy pizza order placed successfully"};
            } else {
                return {false, "", "Legacy pizza SDK rejected ticket"};
            }
        } else {
            return standardPartner_->placeOrder(req);
        }
    }
};

int main() {
    auto standard = std::make_shared<StandardRestaurantPartner>();
    NaiveOrderService service(standard);

    OrderRequest o1{"ORD-101", "+919876543210", "Paneer Tikka Roll", 220.0};
    service.dispatchOrder(o1, false);

    OrderRequest o2{"ORD-102", "+919123456789", "Pepperoni", 450.50};
    service.dispatchOrder(o2, true);

    return 0;
}
OrderService violates the Open-Closed Principle (OCP)

Every time an external restaurant with an idiosyncratic POS SDK joins our platform, OrderService must be modified with new branching logic and conversion math.

Third-party SDK details leak into core domain logic

Low-level C-style strings, paise calculations, and vendor status codes clutter the high-level order orchestration pipeline, degrading maintainability.

Fragile tests and merge conflicts across teams

Multiple teams onboarding different restaurant partners constantly edit the central OrderService class simultaneously.

03

Step 2 β€” The fix: Adapter (Object Adapter)

Core idea in one sentence

Convert the interface of an existing class into another interface that clients expect, allowing classes with incompatible interfaces to collaborate.

We create LegacyPizzaAdapter which implements our standard RestaurantPartner interface and wraps an instance of LegacyPizzaSdk. When placeOrder(order) is called on the adapter, it translates rupee doubles into integer paise, maps item names to legacy SKU codes, and delegates to submitLegacyTicket(). OrderService talks only to RestaurantPartner.

Pattern roles in our story
Target (Interface)

RestaurantPartner β€” the clean standard interface used by OrderService (placeOrder(const OrderRequest&)).

Adaptee (Legacy SDK)

LegacyPizzaSdk β€” third-party vendor SDK with incompatible types (const char*, int64_t paise).

Adapter

LegacyPizzaAdapter β€” implements RestaurantPartner, wraps LegacyPizzaSdk, and handles unit translation.

Client

OrderService β€” dispatches orders through RestaurantPartner without knowing whether the recipient is a modern API or a legacy SDK.

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