Implement the Low Level Design (LLD) of a pizza pricing system.
The system should support:
Your implementation should be extensible so that new pricing rules can be added later (for example: combos, promos, size-based discounts).
Use the Decorator Design Pattern.
Each topping has a per-serving cost.
| Topping | Cost per serving |
|---|---|
| cheeseburst | 100 |
| corn | 50 |
| onion | 30 |
| capsicum | 50 |
| pineapple | 60 |
| mushroom | 40 |
Cheeseburst is considered unhealthy food and attracts more tax.
If at least one serving of cheeseburst is present:
Example:
base tax = 10
uplift = 0.30 × 10 = 3
new tax = 13
Additional cheeseburst servings do not increase tax further.
Cheeseburst pricing rule:
Example:
3 servings → 100 + 70 + 70 = 240
mushroom is considered healthy food.
It cannot be combined with cheeseburst.
Rules:
If violated:
addTopping() returns false
No state change occurs
PizzaPricing(int basePrice, int taxPercentage, String size)
100 ≤ basePrice ≤ 10000
basePrice is always a multiple of 100
0 ≤ taxPercentage ≤ 1000
Example interpretation:
taxPercentage = 1000
means tax = 1000% = 10 × base price
Example:
basePrice = 200
taxPercentage = 1000
tax = 1000/100 × 200 = 2000
final price = 200 + 2000 = 2200
Another example:
basePrice = 200
taxPercentage = 18
tax = 18/100 × 200 = 36
final price = 236
size ∈ { small, medium, large }
All constructor inputs are guaranteed to be valid.
boolean addTopping(String topping, int servingsCount)
servingsCount is a valid positive integerint getFinalPrice()
Subtotal = basePrice + Σ(topping costs applied)
Taxable Base = Subtotal
Tax rate starts with the constructor supplied taxPercentage.
Rules may modify the tax rate (example: cheeseburst uplift).
Tax Amount = (Tax Rate / 100) × Subtotal
Final Price (pre-round) = Subtotal + Tax Amount
To convert the final price to integer:
(int)(x + 0.5)
Examples:
4.6 → 5
4.51 → 5
4.49 → 4
4.5 → 5
PizzaPricing p = new PizzaPricing(200, 10, "small");
p.addTopping("cheeseburst", 1); // true
p.addTopping("onion", 2); // true
int price = p.getFinalPrice(); // 407
base = 200
toppings
cheeseburst = 100
onion = 2 × 30 = 60
toppings total = 160
subtotal = 200 + 160 = 360
Cheeseburst tax uplift:
tax = 10 → 13
tax amount = 13% of 360 = 46.8
final price = 360 + 46.8 = 406.8
rounded = 407
PizzaPricing q = new PizzaPricing(350, 8, "medium");
q.addTopping("mushroom", 2); // true
q.addTopping("cheeseburst", 1); // false
int price = q.getFinalPrice(); // 464
base = 350
toppings
mushroom = 2 × 40 = 80
subtotal = 350 + 80 = 430
tax = 8% of 430 = 34.4
final price = 430 + 34.4 = 464.4
rounded = 464
This question is testing Decorator Pattern + Rule extensibility. The key idea: every topping decorates the base pizza and modifies price/tax behavior.
I'll show a clean interview-quality C++ design that is extensible.
We separate concerns:
Pizza
├── BasePizza
└── ToppingDecorator
├── CheeseBurst
├── Onion
├── Corn
├── Capsicum
├── Pineapple
└── Mushroom
Each topping wraps the pizza and modifies behavior.
class Pizza {
public:
virtual double getSubtotal() = 0;
virtual double getTaxRate() = 0;
virtual ~Pizza() {}
};
class BasePizza : public Pizza {
private:
int basePrice;
double taxRate;
public:
BasePizza(int price, int tax) {
basePrice = price;
taxRate = tax;
}
double getSubtotal() override {
return basePrice;
}
double getTaxRate() override {
return taxRate;
}
void setTaxRate(double newRate) {
taxRate = newRate;
}
};
class ToppingDecorator : public Pizza {
protected:
Pizza* pizza;
public:
ToppingDecorator(Pizza* p) {
pizza = p;
}
};
Handles:
class CheeseBurst : public ToppingDecorator {
private:
int servings;
public:
CheeseBurst(Pizza* p, int s) : ToppingDecorator(p) {
servings = s;
}
double getSubtotal() override {
double cost = 100;
if(servings > 1)
cost += (servings - 1) * 70;
return pizza->getSubtotal() + cost;
}
double getTaxRate() override {
double rate = pizza->getTaxRate();
return rate * 1.3; // +30%
}
};
Example Onion:
class Onion : public ToppingDecorator {
private:
int servings;
public:
Onion(Pizza* p, int s) : ToppingDecorator(p) {
servings = s;
}
double getSubtotal() override {
return pizza->getSubtotal() + servings * 30;
}
double getTaxRate() override {
return pizza->getTaxRate();
}
};
Example Mushroom:
class Mushroom : public ToppingDecorator {
private:
int servings;
public:
Mushroom(Pizza* p, int s) : ToppingDecorator(p) {
servings = s;
}
double getSubtotal() override {
return pizza->getSubtotal() + servings * 40;
}
double getTaxRate() override {
return pizza->getTaxRate();
}
};
This class enforces business rules.
class PizzaPricing {
private:
Pizza* pizza;
bool hasCheeseBurst = false;
bool hasMushroom = false;
public:
PizzaPricing(int basePrice, int tax, string size) {
pizza = new BasePizza(basePrice, tax);
}
bool addTopping(string topping, int servings) {
if(topping == "cheeseburst") {
if(hasMushroom) return false;
pizza = new CheeseBurst(pizza, servings);
hasCheeseBurst = true;
return true;
}
if(topping == "mushroom") {
if(hasCheeseBurst) return false;
pizza = new Mushroom(pizza, servings);
hasMushroom = true;
return true;
}
if(topping == "onion") {
pizza = new Onion(pizza, servings);
return true;
}
if(topping == "corn") {
pizza = new Onion(pizza, servings); // similar structure
return true;
}
if(topping == "capsicum") {
pizza = new Onion(pizza, servings);
return true;
}
if(topping == "pineapple") {
pizza = new Onion(pizza, servings);
return true;
}
return false;
}
int getFinalPrice() {
double subtotal = pizza->getSubtotal();
double taxRate = pizza->getTaxRate();
double tax = subtotal * taxRate / 100.0;
double finalPrice = subtotal + tax;
return (int)(finalPrice + 0.5);
}
};
PizzaPricing p(200, 10, "small");
p.addTopping("cheeseburst",1);
p.addTopping("onion",2);
cout << p.getFinalPrice();
Result:
407
Decorator Pattern
PizzaWithOnion
PizzaWithCheese
PizzaWithCheeseAndOnion
PizzaWithCheeseAndOnionAndCorn
Decorator avoids exponential combinations.
Add new rule:
Example Combo topping
class ComboDecorator : public ToppingDecorator
No changes required to existing pizza classes.
Operations:
| Operation | Complexity |
|---|---|
| addTopping | O(1) |
| getFinalPrice | O(number_of_toppings) |
Common follow-ups:
small 1x
medium 1.2x
large 1.5x
buy 2 onion get 1 free
max 10 toppings