Integrating a Partner Restaurant's Legacy API
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.
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.
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.
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.
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.
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.
The product ticket
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.
- β’
Integrate Bella Pizza without modifying their proprietary third-party SDK (we do not own the SDK source code).
- β’
Do NOT add vendor-specific
if/elsechecks, paise conversions, or item-code maps insideOrderService. - β’
Ensure
OrderServiceinteracts with Bella Pizza seamlessly via our standardRestaurantPartnerinterface.
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.
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.
#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;
}Every time an external restaurant with an idiosyncratic POS SDK joins our platform, OrderService must be modified with new branching logic and conversion math.
Low-level C-style strings, paise calculations, and vendor status codes clutter the high-level order orchestration pipeline, degrading maintainability.
Multiple teams onboarding different restaurant partners constantly edit the central OrderService class simultaneously.
Step 2 β The fix: 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.
RestaurantPartner β the clean standard interface used by OrderService (placeOrder(const OrderRequest&)).
LegacyPizzaSdk β third-party vendor SDK with incompatible types (const char*, int64_t paise).
LegacyPizzaAdapter β implements RestaurantPartner, wraps LegacyPizzaSdk, and handles unit translation.
OrderService β dispatches orders through RestaurantPartner without knowing whether the recipient is a modern API or a legacy SDK.
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.
First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.