One idea
Prefer composition when your object “has a” helper or part. Use inheritance only when your object truly “is a” specialised version of another object.
Composition keeps your feature easier to change. You can replace one part without rewriting the whole class.
Why this matters
In hackathon code, inheritance often starts clean and becomes confusing by demo day. A base class gets too many methods because every child needs something slightly different.
Composition avoids that. You build small classes and pass them into the feature class. The main class coordinates them.
Common wrong turn
Do not create a parent class just because two classes share one or two lines of code. Shared code is not always a parent-child relationship.
For example, a FoodOrder and a CabRide may both have a price. That does not mean both should inherit from BillableThing. They may just use the same PriceCalculator.
Inheritance version
This looks fine at first. But every new payment type can force changes in the parent class. The parent starts knowing too much.
class Order:
def __init__(self, amount):
self.amount = amount
def pay_by_upi(self, upi_id):
print(f"Paid ₹{self.amount} using UPI: {upi_id}")
def pay_by_card(self, card_last4):
print(f"Paid ₹{self.amount} using card ending {card_last4}")
class FoodOrder(Order):
def __init__(self, amount, restaurant_name):
super().__init__(amount)
self.restaurant_name = restaurant_nameComposition version
Here, FoodOrder has a payment method. It does not inherit payment behaviour. It uses another object to do that job.
This is easier to test. You can test FoodOrder separately from UPI payments.
class UpiPayment:
def __init__(self, upi_id):
self.upi_id = upi_id
def pay(self, amount):
return f"Paid ₹{amount} using UPI: {self.upi_id}"
class FoodOrder:
def __init__(self, amount, restaurant_name, payment_method):
self.amount = amount
self.restaurant_name = restaurant_name
self.payment_method = payment_method
def checkout(self):
return self.payment_method.pay(self.amount)
payment = UpiPayment("student@oksbi")
order = FoodOrder(249, "Campus Canteen", payment)
print(order.checkout())How to decide
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Use AI carefully
You can ask ChatGPT or Gemini: “Refactor this class to prefer composition over inheritance. Keep the same behaviour.” Then check the answer yourself.
Check that the new small classes have clear jobs, the main feature class is still readable, and the code still runs with the same sample input.
Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done