Identify Core Objects in LLD Interviews

Updated 2026-03-11

TL;DR

Identifying core objects means extracting the main entities (nouns) from a problem description and determining their attributes (data) and behaviors (methods). This systematic approach transforms requirements into a class structure, forming the foundation of your object-oriented design. Mastering this skill is critical for design interviews where you must quickly translate real-world scenarios into code.

Prerequisites: Basic understanding of classes and objects, familiarity with attributes and methods, knowledge of what OOP is and why we use it. You should be comfortable reading a problem statement and understanding basic requirements.

After this topic: Identify and extract core objects from problem descriptions, determine appropriate attributes and methods for each object, distinguish between entities that should be classes versus simple data types, and create a preliminary class structure that serves as the foundation for an OOP design.

Core Concept

What Are Core Objects?

Core objects are the main entities in your system that have both state (data) and behavior (actions). They represent the “things” your application manages and manipulates. In OOP design, identifying these objects is your first step — before writing any code, you need to know what you’re building.

Think of core objects as the nouns in your problem description that need to do something or have something done to them. Not every noun becomes a class, but every class starts as a noun.

The Three-Step Process

Step 1: Extract Nouns (Potential Objects)

Read the problem statement and underline every noun. These are your candidates for objects. For example, in “A library system manages books, members, and loans,” you have: library, system, books, members, and loans.

Step 2: Identify Attributes (State)

For each potential object, ask: “What information does this thing need to know about itself?” A Book needs a title, author, ISBN. A Member needs a name, ID, contact info. These become your class attributes — the data each object holds.

Step 3: Identify Behaviors (Methods)

Ask: “What can this object do?” and “What can be done to this object?” A Book can be checked out, returned, or reserved. A Member can borrow books, return books, or pay fines. These actions become your methods.

Filtering Your Candidates

Not every noun becomes a class. Filter out:

  • Attributes disguised as nouns: “Title” is not a class; it’s an attribute of Book
  • Primitives: Simple data types like strings or numbers rarely need their own class
  • The system itself: “Library System” is usually not an object; it’s what you’re building
  • Synonyms: “User” and “Member” likely refer to the same entity

Why This Matters

Identifying core objects correctly sets up everything else. Get this wrong, and you’ll struggle with awkward designs, bloated classes, or missing functionality. Get it right, and the rest of your design flows naturally. In interviews, this is where you demonstrate your ability to think in objects rather than procedures.

Visual Guide

From Problem to Objects

graph TD
    A[Problem Statement] --> B[Extract Nouns]
    B --> C[Filter Candidates]
    C --> D[Identify Attributes]
    C --> E[Identify Behaviors]
    D --> F[Core Objects with State]
    E --> F
    F --> G[Class Structure]
    
    style A fill:#e1f5ff
    style G fill:#c8e6c9

The systematic process of transforming a problem description into core objects with attributes and behaviors.

Library System Core Objects

classDiagram
    class Book {
        -title: string
        -author: string
        -isbn: string
        -isAvailable: bool
        +checkout()
        +return()
        +getDetails()
    }
    
    class Member {
        -memberId: string
        -name: string
        -email: string
        -borrowedBooks: List
        +borrowBook()
        +returnBook()
        +viewHistory()
    }
    
    class Loan {
        -loanId: string
        -book: Book
        -member: Member
        -dueDate: date
        +calculateFine()
        +extend()
        +complete()
    }
    
    Member "1" -- "*" Loan
    Book "1" -- "*" Loan

Core objects for a library system showing attributes (state) and methods (behavior). Notice how relationships emerge naturally from the objects.

Examples

Example 1: E-Commerce Shopping Cart

Problem Statement: “Design a shopping cart system where customers can add products, update quantities, and checkout. Each product has a name, price, and stock quantity.”

Step 1: Extract Nouns Nouns: shopping cart, system, customers, products, quantities, checkout, name, price, stock quantity

Step 2: Filter and Identify Core Objects

  • ShoppingCart: Manages items being purchased
  • Customer: The person shopping
  • Product: Items available for purchase
  • ❌ System: That’s what we’re building, not an object
  • ❌ Name, price, quantity: These are attributes, not objects

Step 3: Define Attributes and Behaviors

class Product:
    """Represents an item available for purchase."""
    
    def __init__(self, product_id, name, price, stock_quantity):
        self.product_id = product_id
        self.name = name
        self.price = price
        self.stock_quantity = stock_quantity
    
    def is_available(self, quantity):
        """Check if requested quantity is in stock."""
        return self.stock_quantity >= quantity
    
    def reduce_stock(self, quantity):
        """Reduce stock after purchase."""
        if self.is_available(quantity):
            self.stock_quantity -= quantity
            return True
        return False


class Customer:
    """Represents a person shopping on the platform."""
    
    def __init__(self, customer_id, name, email):
        self.customer_id = customer_id
        self.name = name
        self.email = email
        self.cart = ShoppingCart(self)
    
    def add_to_cart(self, product, quantity):
        """Add product to customer's cart."""
        return self.cart.add_item(product, quantity)


class ShoppingCart:
    """Manages items a customer intends to purchase."""
    
    def __init__(self, customer):
        self.customer = customer
        self.items = {}  # {product_id: (product, quantity)}
    
    def add_item(self, product, quantity):
        """Add or update product quantity in cart."""
        if not product.is_available(quantity):
            return False
        
        if product.product_id in self.items:
            _, current_qty = self.items[product.product_id]
            self.items[product.product_id] = (product, current_qty + quantity)
        else:
            self.items[product.product_id] = (product, quantity)
        return True
    
    def calculate_total(self):
        """Calculate total cost of items in cart."""
        total = 0
        for product, quantity in self.items.values():
            total += product.price * quantity
        return total
    
    def checkout(self):
        """Process the purchase."""
        total = self.calculate_total()
        # Reduce stock for each item
        for product, quantity in self.items.values():
            product.reduce_stock(quantity)
        self.items.clear()
        return total


# Usage Example
product1 = Product("P001", "Laptop", 999.99, 10)
product2 = Product("P002", "Mouse", 29.99, 50)

customer = Customer("C001", "Alice", "alice@example.com")
customer.add_to_cart(product1, 1)
customer.add_to_cart(product2, 2)

print(f"Cart total: ${customer.cart.calculate_total():.2f}")
# Output: Cart total: $1059.97

total = customer.cart.checkout()
print(f"Purchase complete: ${total:.2f}")
# Output: Purchase complete: $1059.97
print(f"Laptop stock remaining: {product1.stock_quantity}")
# Output: Laptop stock remaining: 9

Key Observations:

  • Product has both data (price, stock) and behavior (check availability, reduce stock)
  • Customer owns a ShoppingCart — this relationship emerged from the problem
  • ShoppingCart manages the collection of items and handles calculations

Try it yourself: Add a remove_item() method to ShoppingCart and a restock() method to Product.


Example 2: Parking Lot System

Problem Statement: “Design a parking lot with multiple levels. Each level has parking spots of different sizes (compact, regular, large). Vehicles of different types (motorcycle, car, bus) need to park in appropriate spots.”

Step 1: Extract Nouns Nouns: parking lot, levels, parking spots, sizes, vehicles, types, motorcycle, car, bus

Step 2: Identify Core Objects

  • ParkingLot: The overall facility
  • Level: A floor in the parking structure
  • ParkingSpot: An individual parking space
  • Vehicle: What needs to be parked (abstract concept)
  • Motorcycle, Car, Bus: Specific vehicle types

Step 3: Define Attributes and Behaviors

from enum import Enum
from abc import ABC, abstractmethod

class VehicleSize(Enum):
    MOTORCYCLE = 1
    COMPACT = 2
    REGULAR = 3
    LARGE = 4

class SpotSize(Enum):
    MOTORCYCLE = 1
    COMPACT = 2
    REGULAR = 3
    LARGE = 4


class Vehicle(ABC):
    """Abstract base for all vehicles."""
    
    def __init__(self, license_plate):
        self.license_plate = license_plate
        self.parking_spot = None
    
    @abstractmethod
    def get_size(self):
        """Return the size category of this vehicle."""
        pass


class Motorcycle(Vehicle):
    def get_size(self):
        return VehicleSize.MOTORCYCLE


class Car(Vehicle):
    def get_size(self):
        return VehicleSize.COMPACT


class Bus(Vehicle):
    def get_size(self):
        return VehicleSize.LARGE


class ParkingSpot:
    """Represents a single parking space."""
    
    def __init__(self, spot_id, size):
        self.spot_id = spot_id
        self.size = size
        self.vehicle = None
    
    def is_available(self):
        """Check if spot is empty."""
        return self.vehicle is None
    
    def can_fit_vehicle(self, vehicle):
        """Check if vehicle size fits this spot."""
        return self.size.value >= vehicle.get_size().value
    
    def park_vehicle(self, vehicle):
        """Park a vehicle in this spot."""
        if not self.is_available():
            return False
        if not self.can_fit_vehicle(vehicle):
            return False
        
        self.vehicle = vehicle
        vehicle.parking_spot = self
        return True
    
    def remove_vehicle(self):
        """Remove vehicle from spot."""
        if self.vehicle:
            self.vehicle.parking_spot = None
            self.vehicle = None


class Level:
    """Represents one floor of the parking lot."""
    
    def __init__(self, level_number):
        self.level_number = level_number
        self.spots = []
    
    def add_spot(self, spot):
        """Add a parking spot to this level."""
        self.spots.append(spot)
    
    def park_vehicle(self, vehicle):
        """Try to park vehicle on this level."""
        for spot in self.spots:
            if spot.is_available() and spot.can_fit_vehicle(vehicle):
                if spot.park_vehicle(vehicle):
                    return spot
        return None
    
    def get_available_spots(self):
        """Count available spots."""
        return sum(1 for spot in self.spots if spot.is_available())


class ParkingLot:
    """Manages the entire parking facility."""
    
    def __init__(self):
        self.levels = []
    
    def add_level(self, level):
        """Add a level to the parking lot."""
        self.levels.append(level)
    
    def park_vehicle(self, vehicle):
        """Find a spot for the vehicle across all levels."""
        for level in self.levels:
            spot = level.park_vehicle(vehicle)
            if spot:
                return spot
        return None
    
    def get_total_available_spots(self):
        """Count all available spots."""
        return sum(level.get_available_spots() for level in self.levels)


# Usage Example
parking_lot = ParkingLot()

# Create Level 1 with mixed spot sizes
level1 = Level(1)
level1.add_spot(ParkingSpot("L1-S1", SpotSize.MOTORCYCLE))
level1.add_spot(ParkingSpot("L1-S2", SpotSize.COMPACT))
level1.add_spot(ParkingSpot("L1-S3", SpotSize.REGULAR))
level1.add_spot(ParkingSpot("L1-S4", SpotSize.LARGE))
parking_lot.add_level(level1)

# Park vehicles
motorcycle = Motorcycle("MOTO-123")
car = Car("CAR-456")
bus = Bus("BUS-789")

spot1 = parking_lot.park_vehicle(motorcycle)
print(f"Motorcycle parked at: {spot1.spot_id if spot1 else 'No spot available'}")
# Output: Motorcycle parked at: L1-S1

spot2 = parking_lot.park_vehicle(car)
print(f"Car parked at: {spot2.spot_id if spot2 else 'No spot available'}")
# Output: Car parked at: L1-S2

spot3 = parking_lot.park_vehicle(bus)
print(f"Bus parked at: {spot3.spot_id if spot3 else 'No spot available'}")
# Output: Bus parked at: L1-S4

print(f"Available spots: {parking_lot.get_total_available_spots()}")
# Output: Available spots: 1

Key Observations:

  • Vehicle is abstract — we identified that Motorcycle, Car, and Bus share common structure
  • ParkingSpot has clear responsibilities: know its size, check availability, manage occupancy
  • Level and ParkingLot form a hierarchy that emerged from “multiple levels”
  • Each object has a single, clear purpose

Java/C++ Note: In Java, you’d use abstract class Vehicle or interface. In C++, you’d use pure virtual functions: virtual VehicleSize getSize() = 0;

Try it yourself: Add a find_vehicle(license_plate) method to ParkingLot that searches all levels for a specific vehicle.

Common Mistakes

1. Making Everything a Class

Mistake: Creating classes for simple attributes like Title, Price, or Color.

# ❌ Over-engineering
class Title:
    def __init__(self, value):
        self.value = value

class Book:
    def __init__(self, title):
        self.title = Title(title)  # Unnecessary wrapper

Why it’s wrong: Not everything needs to be an object. Simple data types (strings, numbers) are fine as attributes. Only create a class when the entity has meaningful behavior or complex state.

Fix: Use primitive types for simple attributes:

# ✅ Appropriate design
class Book:
    def __init__(self, title):
        self.title = title  # Just a string

2. Confusing the System with an Object

Mistake: Creating a class for the system itself, like LibrarySystem or ShoppingCartSystem, and putting all logic there.

# ❌ God object anti-pattern
class LibrarySystem:
    def __init__(self):
        self.books = []
        self.members = []
    
    def checkout_book(self, book_id, member_id):
        # All logic in one place
        pass

Why it’s wrong: This creates a “god object” that does everything. The system is what you’re building, not an object within it. Your objects should interact with each other, not through a central controller.

Fix: Distribute responsibilities to the actual entities:

# ✅ Objects with clear responsibilities
class Member:
    def checkout_book(self, book):
        if book.is_available():
            self.borrowed_books.append(book)
            book.checkout()

3. Missing Core Objects

Mistake: Failing to identify important entities that represent relationships or transactions.

# ❌ Missing the Loan object
class Book:
    def __init__(self):
        self.borrowed_by = None  # Just storing member
        self.due_date = None     # Loose data

Why it’s wrong: When a Book is borrowed by a Member, that relationship has its own data (due date, fine amount) and behavior (calculate fine, extend loan). This deserves its own object.

Fix: Create objects for significant relationships:

# ✅ Loan as a first-class object
class Loan:
    def __init__(self, book, member, due_date):
        self.book = book
        self.member = member
        self.due_date = due_date
    
    def calculate_fine(self):
        # Behavior belongs to the relationship
        pass

4. Focusing Only on Attributes, Ignoring Behavior

Mistake: Identifying objects but only listing their data, creating “anemic” objects.

# ❌ Anemic object (just data)
class Product:
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock
    # No methods — just a data container

Why it’s wrong: Objects should encapsulate both data and the operations on that data. If your object has no methods, it’s not really an object — it’s just a struct.

Fix: Add behavior that operates on the object’s state:

# ✅ Object with behavior
class Product:
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock
    
    def is_available(self, quantity):
        return self.stock >= quantity
    
    def reduce_stock(self, quantity):
        if self.is_available(quantity):
            self.stock -= quantity
            return True
        return False

5. Creating Too Many Small Objects Too Early

Mistake: Breaking down into tiny objects before understanding the core structure.

# ❌ Premature decomposition
class Street:
    pass

class City:
    pass

class ZipCode:
    pass

class Address:
    def __init__(self):
        self.street = Street()
        self.city = City()
        self.zip = ZipCode()

Why it’s wrong: Start with core objects first. You can always refactor later. Over-decomposing early leads to complexity without clarity.

Fix: Start simple, refactor when needed:

# ✅ Start with essential structure
class Address:
    def __init__(self, street, city, zip_code):
        self.street = street
        self.city = city
        self.zip_code = zip_code
    # Refactor to objects later if behavior emerges

Interview Tips

1. Talk Through Your Process Out Loud

Do this: “Let me start by identifying the main entities. I see ‘user,’ ‘post,’ and ‘comment’ in the problem. Let me list what each needs to know and do…”

Why: Interviewers want to see your thought process. Verbalizing shows you’re systematic, not just guessing. Even if you make a mistake, they can guide you if they understand your reasoning.


2. Ask Clarifying Questions About Entities

Do this: “Should a ‘Reservation’ be its own object, or just an attribute of ‘Room’? Does it need to track history or calculate fees?”

Why: This shows you understand that design decisions depend on requirements. It also prevents you from over-engineering or under-engineering. Interviewers appreciate when you validate assumptions.


3. Use the “Has-A” and “Does-A” Test

Do this: For each potential object, ask:

  • “What does this HAVE?” (attributes)
  • “What does this DO?” (methods)

If you can’t answer both, it might not be a core object.

Example: “A Book HAS a title, author, ISBN. A Book DOES get checked out, returned, reserved. So Book is definitely a core object.”

Why: This gives you a quick filter and demonstrates structured thinking.


4. Start with 3-5 Core Objects, Then Expand

Do this: “I’ll start with User, Post, and Comment as my core objects. Once we have those defined, we can add Like or Notification if needed.”

Why: Interviewers want to see you prioritize. Starting with too many objects shows poor judgment. Starting with core entities shows you understand what’s essential versus what’s nice-to-have.


5. Draw It Out

Do this: Sketch boxes for each object with attributes and methods listed. Draw arrows showing relationships.

Why: Visual representation helps both you and the interviewer stay aligned. It’s easier to spot missing objects or awkward relationships when you see them on paper/whiteboard.


6. Watch for Relationship Objects

Do this: “Wait — when a User enrolls in a Course, that enrollment has its own data like enrollment date and grade. Should Enrollment be its own object?”

Why: Many candidates miss objects that represent relationships or transactions (Order, Reservation, Enrollment, Loan). Identifying these shows advanced thinking.


7. Validate Your Objects Against Use Cases

Do this: “Let me check: if a user wants to checkout a book, I need Book.checkout() and Member.borrow(). That works. If we need to calculate fines, where does that logic go? Maybe we need a Loan object…”

Why: Walking through scenarios helps you catch missing objects or misplaced responsibilities. It shows you’re thinking about actual usage, not just abstract structure.


8. Don’t Overthink Primitives

Do this: “I’ll use a string for email address. If we need validation later, we can refactor to an Email class.”

Why: Interviewers don’t want to see you create classes for every single attribute. Show pragmatism — start simple, mention where you’d refactor if requirements grew.


Common Interview Question Patterns

  • “Design a parking lot” → Look for: ParkingLot, Level, ParkingSpot, Vehicle (and subtypes)
  • “Design a library system” → Look for: Book, Member, Loan (not just Book and Member!)
  • “Design an online store” → Look for: Product, Customer, ShoppingCart, Order (Order is often missed)
  • “Design a social media feed” → Look for: User, Post, Comment, Like (Like might be its own object if it has timestamps, etc.)

The pattern: Always look for the entities (nouns), the relationships between them (often objects themselves), and the transactions/events (also often objects).

Key Takeaways

  • Core objects are the main entities in your system that have both state (attributes) and behavior (methods). Extract them by identifying nouns in the problem statement, then filtering for entities that need to do something or have something done to them.

  • Use a three-step process: (1) Extract nouns from requirements, (2) Identify attributes (what the object knows), (3) Identify behaviors (what the object does). Not every noun becomes a class — filter out primitives, attributes disguised as nouns, and the system itself.

  • Relationships and transactions often need their own objects. When two entities interact (User borrows Book), that relationship may have its own data and behavior (Loan with due date and fine calculation). Don’t miss these.

  • Start with 3-5 core objects and expand. Prioritize the essential entities first, then add supporting objects as needed. This shows good judgment and prevents over-engineering early in the design process.

  • In interviews, verbalize your process and validate with use cases. Talk through how you’re identifying objects, ask clarifying questions, and walk through scenarios to ensure your objects can handle the required functionality. Drawing a diagram helps both you and the interviewer stay aligned.