Four Pillars • SOLID • Design Patterns • Class Modelling • 2026

OOPs Interview Questions

30 questions What each one tests, an answer frame, a spoken answer 33 min read

This page is for anyone facing an object-oriented programming round, whether it sits inside a Java, C#, C++ or Python interview or stands alone. Most OOPs rounds start with the four pillars and class versus object, move to overloading, overriding, interfaces and composition, then test SOLID one principle at a time. Stronger rounds add design patterns, when not to use them, and a live class model such as a parking lot. Each question shows what the interviewer is really checking, the shape of a strong answer and a short answer you can say out loud. Swap in your own examples as you practise.

Search all questions by round, difficulty and level, or save the ones you want to practise.

Core Concepts 6 questions

Easy Technical round Fresher Practice question

1. What are the four pillars of object-oriented programming? Give me a plain, everyday example for each one.

What the interviewer is really testing:
Whether you can explain each pillar in your own words with an example, rather than reciting four textbook definitions you can't apply.
Answer frame:

Encapsulation: keep data and the methods that change it together, and hide the internals.

Abstraction: show only what the caller needs, hide how it's done.

Inheritance: a new class reuses and extends an existing one.

Polymorphism: one call, different behaviour depending on the actual object.

Sample spoken answer:

"The four are encapsulation, abstraction, inheritance and polymorphism. Encapsulation is a bank account class where the balance is private and the only way to change it is deposit or withdraw, which check the rules. Abstraction is a car's pedals: I press the brake without knowing whether it's disc or drum brakes underneath. In code, that's a PaymentService with a pay method that hides which provider it calls. Inheritance is a SavingsAccount that reuses everything in Account and adds interest. Polymorphism is having a list of shapes and calling area on each one: a circle and a square each run their own version, and the loop doesn't care which is which. The way I remember it, encapsulation protects the data, abstraction hides complexity, inheritance reuses code, and polymorphism lets one piece of code work with many types."

Red flag to avoid:

Listing the four names with no examples, or giving the same example for encapsulation and abstraction without being able to say how they differ.

They may ask next:
  • Which of the four do you think causes the most trouble when it's overused, and why?
  • Can you have polymorphism without inheritance?
Say it in 60 seconds
Easy Technical round Fresher Practice question

2. What's the difference between a class and an object, and what actually gets created when you make a new object?

What the interviewer is really testing:
Whether you have a working mental model of instances, fields and references, not just the word blueprint.
Answer frame:

Class: the definition: which fields each object has and which methods it supports.

Object: one instance with its own values for those fields.

Memory: each object gets its own storage for instance fields; the method code is shared, not copied per object.

Sample spoken answer:

"A class is the definition. It says every Student has a name and a roll number and can do things like enroll in a course. An object is one actual student built from that definition, with its own values. If I create two Student objects, each has its own name and roll number, but they share the same method code; methods aren't copied into every object. In Java or C#, when I write new Student, the object is allocated on the heap and my variable only holds a reference to it, so assigning that variable to another one gives two references to the same object, not a copy. C++ also lets me create an object directly on the stack. So the class exists once, and there can be zero, one or a million objects of it at run time."

Red flag to avoid:

Saying each object carries its own copy of every method, or not knowing that object variables usually hold references.

They may ask next:
  • If I assign one object variable to another and change a field through the second one, what does the first one see?
  • Can a class exist in a running program without any objects of it being created?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

3. People often mix up encapsulation and abstraction. How would you tell them apart?

What the interviewer is really testing:
Whether you understand that one is about protecting state and the other is about the level of detail you expose, since the two are easy to blur.
Answer frame:

Encapsulation: bundle state with the methods that guard it; stop outsiders changing it directly.

Abstraction: decide what idea to expose and hide the how behind it.

Together: abstraction picks the shape of the interface, encapsulation enforces it.

Sample spoken answer:

"I think of abstraction as a design decision about what to show, and encapsulation as the mechanism that protects what's hidden. Abstraction is choosing that a Notifier has one method, send, and callers never learn whether it goes by email or text message. Encapsulation is inside a class: the fields are private and every change goes through a method that keeps the object valid, like a withdraw method that refuses to take the balance below zero. You can have one without the other. A class with all public fields and one simple method has an abstraction but no encapsulation, because anyone can reach in and break it. So abstraction answers what does this thing do, and encapsulation answers who is allowed to touch its insides."

Red flag to avoid:

Saying they are the same thing, or defining encapsulation only as using private fields with no idea of protecting the object's rules.

They may ask next:
  • Is making every field private and adding a getter and setter for each one real encapsulation?
  • Where does an interface fit: abstraction, encapsulation or both?
Say it in 60 seconds
Easy Technical round Fresher Practice question

4. What is a constructor for, and how is it different from an ordinary method?

What the interviewer is really testing:
Whether you see the constructor as the place that makes an object valid from the start, and know the basic rules around it.
Answer frame:

Purpose: runs once when the object is created and puts it in a valid state.

Rules: in Java, C# and C++ it has the class name, no return type, and can be overloaded.

Defaults and chaining: a no-argument one is supplied only if you write none; one constructor can call another or the parent's.

Sample spoken answer:

"A constructor runs exactly once, when the object is created, and its job is to make the object valid from the first moment. If a BankAccount must always have an owner, I take the owner in the constructor, so there's no way to get an account without one. Unlike a normal method, in Java, C# or C++ it has the same name as the class and no return type, and I can't call it again on an existing object. I can overload it, say one version with just a name and another with a name and an opening balance, and have the shorter one call the longer one so the setup logic lives in one place. If I don't write any constructor, the compiler gives me a default one with no arguments, but as soon as I write one that takes arguments, that free default goes away. In Python the closest thing is __init__, which sets up an object that's already been created."

Red flag to avoid:

Describing the constructor as just a method that sets fields, with no idea of guaranteeing a valid object.

They may ask next:
  • In what order do constructors run when a subclass object is created?
  • Why is it risky for a constructor to call a method that subclasses can override?
Say it in 60 seconds
Easy Technical round Fresher Practice question

5. What are access modifiers for, and how do you decide whether a member should be private, protected or public?

What the interviewer is really testing:
Whether you treat visibility as a design choice that protects the object and keeps change cheap, not just as keywords.
Answer frame:

Purpose: control who can see and change a member, which protects the object's rules.

Default: start private, open up only when there's a real caller.

Protected and public: protected is a promise to subclasses, public a promise to everyone; both are hard to take back.

Sample spoken answer:

"Access modifiers control who can see and use a field or method. Private means only the class itself, protected adds subclasses, and in Java the same package too, and public means anyone. Languages add their own extras, like package-level access in Java or internal in C#, and Python only has naming conventions with underscores that aren't enforced. My rule is to start everything private and open it up only when there's a real need. Everything public is a promise: once other code depends on it, changing it breaks them. Protected is a promise too, to every subclass anyone ever writes, so I use it less than people expect. Fields stay private almost always, and I expose behaviour through methods that keep the object valid, rather than handing out raw access to the data."

Red flag to avoid:

Making fields public for convenience, or not being able to say why narrower visibility is safer.

They may ask next:
  • Why can a protected field be as risky as a public one?
  • How do you test logic that lives in a private method?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

6. When should a method or field be static instead of belonging to each object? What problems do too many statics cause?

What the interviewer is really testing:
Whether you know static means one copy per class, and understand that mutable static state is global state with all its testing and threading costs.
Answer frame:

Static: belongs to the class, one copy shared by all; a static method has no this.

Good uses: constants, pure helper functions, named factory methods.

Costs: mutable statics are global state: shared across threads, hard to reset in tests, hard to swap out.

Sample spoken answer:

"An instance field belongs to each object, so two orders have their own totals. A static field belongs to the class, so there's one copy shared by every object, and a static method runs without any particular object, which means it can't touch instance fields directly. I make something static when it genuinely doesn't depend on an object: constants, pure helpers like a function that converts units, or a named factory method like fromJson. The trouble starts with mutable static state. It's really a global variable: every thread shares it, one test can leave it dirty for the next, and code that calls a static method can't easily be given a fake version in tests. Also, in languages like Java, static methods aren't overridden polymorphically. So I keep statics stateless and pass real dependencies in as objects."

Red flag to avoid:

Making things static just to avoid creating an object, or not seeing that a mutable static field is shared global state.

They may ask next:
  • Why is a static counter of created objects a problem in a multithreaded program?
  • How would you test a class that calls a static method which hits the network?
Say it in 60 seconds

Inheritance & Polymorphism 4 questions

Easy Technical round Fresher, Mid-level Practice question

7. Show me one example of overloading and one of overriding from code you've written. Which one is decided at compile time and which at run time?

What the interviewer is really testing:
Whether you can tie the two terms to real code and to static versus dynamic polymorphism, instead of mixing them up under pressure.
Answer frame:

Overloading: same method name, different parameter lists, picked by the compiler from the argument types.

Overriding: a subclass replaces an inherited method with the same signature, picked at run time from the real object.

Gotcha: a different return type alone is not a valid overload in Java, C# or C++.

Sample spoken answer:

"In a logging helper I wrote, I had log with just a message and log with a message and an exception. That's overloading: same name, different parameters, and the compiler picks which one to call from the arguments I pass, so it's decided at compile time. For overriding, I had a base Report class with a render method, and PdfReport and CsvReport each overrode it. The code held a Report reference and called render, and which version ran depended on the actual object at run time. That's dynamic dispatch, the heart of runtime polymorphism. One trap: changing only the return type doesn't make a valid overload. Also, Python doesn't overload by signature at all; a second method with the same name simply replaces the first, so there I'd use default arguments instead."

Red flag to avoid:

Swapping the two definitions, or claiming a method can be overloaded just by changing its return type.

They may ask next:
  • Can you override a static method? What actually happens if you try?
  • What does an override annotation or keyword protect you from?
Say it in 60 seconds
Medium Coding round Fresher, Mid-level Practice question

8. How does polymorphism help you get rid of a long if-else chain that checks an object's type? Show me with a small example.

What the interviewer is really testing:
Whether you can use polymorphism as a practical refactoring tool, which is what it's for, rather than just define it.
Answer frame:

Smell: the same switch on a type field repeated in several places.

Fix: give each type its own class with a common method, and let each class carry its own behaviour.

Payoff: adding a type means adding a class, not hunting down every switch.

Sample spoken answer:

"The smell is code like if channel equals email, do this; else if sms, do that; and the same chain copied into three other functions. Every new channel means editing all of them, and missing one is a bug. With polymorphism I define a common type, say a Notifier with a send method, and write one class per channel. The calling code just loops over notifiers and calls send; it never asks what type it has. Each class carries its own behaviour, so adding push notifications is one new class and nothing else changes. I'd still keep a single place, like a factory, that turns a config value into the right object, because some code has to make that choice once. But it's one place, not scattered everywhere."

Code:
from abc import ABC, abstractmethod

class Notifier(ABC):
    @abstractmethod
    def send(self, user, text): ...

class EmailNotifier(Notifier):
    def send(self, user, text):
        print(f"email to {user}: {text}")

class SmsNotifier(Notifier):
    def send(self, user, text):
        print(f"sms to {user}: {text}")

def alert(notifiers, user, text):
    for n in notifiers:          # no type checks here
        n.send(user, text)

alert([EmailNotifier(), SmsNotifier()], "asha", "Your order shipped")
Red flag to avoid:

Keeping the type checks inside the new classes, or not seeing that the win is adding a type without editing old code.

They may ask next:
  • Is a switch on type ever the better choice than polymorphism?
  • Where does the code that decides which Notifier to create belong?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

9. What's the difference between an abstract class and an interface, and how do you decide which one to use in a design?

What the interviewer is really testing:
Whether you choose between them by what you are modelling: shared code and state for close relatives versus a capability many unrelated types can offer.
Answer frame:

Abstract class: related types that share state and some implementation; can have fields and constructors.

Interface: a contract for a capability; a class can take on several; no instance state.

Common combo: interface as the public type, abstract base as an optional helper for implementers.

Sample spoken answer:

"I ask what I'm modelling. If I have a family of closely related types that share real state and code, like several report types that all have a title, an author and the same header logic, an abstract base class fits. It can hold fields, a constructor and finished methods, and leave just one or two abstract ones for each subclass. If instead I'm describing a capability that very different types might have, like being exportable or comparable, that's an interface. A class can implement several interfaces but usually extend only one base class, so interfaces keep my options open. Modern languages blur this a bit with default methods, but an interface still can't hold per-object state. In practice I often use both: callers depend on the interface, and an abstract class gives implementers a head start."

Red flag to avoid:

Answering only with syntax rules and never saying what kind of relationship each one models.

They may ask next:
  • Why is it safer for callers to depend on the interface rather than the abstract class?
  • What goes wrong when you add a new abstract method to a base class with many subclasses?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

10. What is the diamond problem in multiple inheritance, and how do different languages deal with it?

What the interviewer is really testing:
Whether you understand the ambiguity itself and know the broad approaches languages take, without inventing details.
Answer frame:

Problem: D inherits from B and C, which both inherit from A; which version of A's method, and how many copies of A's state?

Approaches: single class inheritance plus interfaces, virtual inheritance, or a fixed method resolution order.

Design lesson: deep multiple inheritance is usually a sign to use composition.

Sample spoken answer:

"Picture class A at the top, B and C both inheriting from it, and D inheriting from both B and C. That's the diamond. If B and C both override a method from A, which one does D get? And does D contain one copy of A's fields or two? Languages handle it differently. Java and C# only allow one base class, so the state problem can't happen; you can implement many interfaces, and in Java if two interfaces give conflicting default methods, the class has to override it and choose. C++ allows it; by default D really does get two copies of A, and you use virtual inheritance to share one. Python allows it and uses a fixed method resolution order so every class appears once and lookups are predictable. In my own designs, if I hit a diamond I usually take it as a hint to use composition instead."

Red flag to avoid:

Saying no language allows multiple inheritance, or being unable to describe the ambiguity itself.

They may ask next:
  • Why is inheriting several interfaces less risky than inheriting several classes?
  • What does virtual inheritance cost in C++?
Say it in 60 seconds

SOLID Principles 5 questions

Medium Technical round Mid-level Practice question

11. What is the Interface Segregation Principle? Show me what a fat interface looks like and how you'd split it.

What the interviewer is really testing:
Whether you can spot an interface that forces classes to implement things they don't need, and split it by what callers actually use.
Answer frame:

Principle: no client should be forced to depend on methods it doesn't use.

Smell: implementers that throw not supported or leave empty bodies.

Fix: split by role, so each caller depends on the small interface it needs.

Sample spoken answer:

"The principle says a class shouldn't be forced to depend on methods it doesn't use. The classic smell is an interface like Machine with print, scan and fax. A cheap home printer has to implement all three, so scan and fax end up throwing not supported, and anyone calling fax on a Machine gets a surprise at run time. I'd split it into Printer, Scanner and Fax, each with its own methods. The office machine implements all three, the basic printer implements only Printer, and the print queue depends only on Printer. That makes each dependency honest, and changes to fax don't force recompiling or retesting code that only prints. I cut interfaces by who uses them, not by guessing, so I don't end up with a hundred one-method interfaces either."

Red flag to avoid:

Thinking the fix is to give the unused methods empty bodies, or splitting every interface into one method each by default.

They may ask next:
  • How is a method that throws not supported also a Liskov problem?
  • How small is too small for an interface?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

12. Explain the Single Responsibility Principle using a class you would split up.

What the interviewer is really testing:
Whether you read single responsibility as one reason to change, tied to who asks for changes, rather than one method per class.
Answer frame:

Principle: a class should have one reason to change.

Test: list who might ask for a change; different people means different responsibilities.

Split: move each responsibility to its own class and let a coordinator use them.

Sample spoken answer:

"The principle says a class should have one reason to change. Take an Invoice class that calculates totals and tax, renders itself as a PDF, and emails itself to the customer. Three different people could ask for changes there: finance changes the tax rules, the design team changes the layout, and ops switches the email provider. Every one of those edits touches the same class and risks breaking the others. I'd keep Invoice for the data and the calculation rules, move PDF output to an InvoiceRenderer, and sending to an InvoiceMailer. Now a layout change can't break tax maths, and each piece is easy to test alone. It doesn't mean one method per class; a class can have many methods as long as they serve the same purpose."

Red flag to avoid:

Saying a class should do only one thing in the sense of one method, or giving an example with no reason to split.

They may ask next:
  • How do you avoid splitting things so finely that the code becomes hard to follow?
  • Where would the code that calls calculate, render and email in order live?
Say it in 60 seconds
Medium Technical round Mid-level Practice question

13. What does the Open/Closed Principle mean in practice? How can code be open for extension but closed for modification?

What the interviewer is really testing:
Whether you can turn the slogan into a concrete technique, adding new behaviour as new code behind an abstraction, and know it's applied where change is expected.
Answer frame:

Meaning: add new behaviour by adding code, not by editing code that already works.

How: put the part that varies behind an interface; new cases become new classes.

Limits: apply it where change is likely, not everywhere up front.

Sample spoken answer:

"It means that when a new requirement arrives, I should be able to add new code rather than reopen classes that are already tested and working. Say I have a report exporter with a switch for CSV and JSON. Every new format means editing that switch and retesting the whole thing. Instead I define an Exporter interface with an export method, and CSV and JSON are two classes behind it. When someone asks for Excel, I write an ExcelExporter and register it; the calling code and the existing exporters don't change at all. So it's open because new formats plug in, and closed because the core isn't touched. I don't do this for everything on day one, though. I usually wait until a second or third variation shows up, so I know which part actually changes."

Red flag to avoid:

Saying classes must never be edited, or adding interfaces everywhere in advance with no expected variation.

They may ask next:
  • Which other SOLID principle does this one depend on to work?
  • Is changing a class to fix a bug a violation of this principle?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

14. Why is a Square class that inherits from Rectangle the classic example of breaking the Liskov Substitution Principle?

What the interviewer is really testing:
Whether you understand substitution as keeping the parent's promised behaviour, not just matching method signatures, and can show a concrete break.
Answer frame:

Principle: code written for the parent must still work correctly with any subclass.

The break: a rectangle promises width and height change independently; a square can't keep that promise.

Fix: don't relate them by inheritance, or make shapes immutable with a shared read-only type.

Sample spoken answer:

"Liskov says anywhere the code expects a Rectangle, I should be able to pass a subclass and nothing should break. In maths a square is a rectangle, so it feels natural to inherit. But a mutable Rectangle promises that setting the width leaves the height alone. A Square must keep both sides equal, so its setters change both. Now a function that sets width to five and height to four and expects an area of twenty gets sixteen from a square. The code compiles fine, every signature matches, and it's still wrong, because the subclass broke the behaviour the parent promised. The fix is to stop forcing the relationship: make them siblings under a read-only Shape with an area method, or make them immutable so there are no setters to break. The lesson is that is-a in real life doesn't guarantee is-a in code."

Code:
class Rectangle:
    def __init__(self, w, h):
        self.w, self.h = w, h
    def set_width(self, w): self.w = w
    def set_height(self, h): self.h = h
    def area(self): return self.w * self.h

class Square(Rectangle):
    def __init__(self, side):
        super().__init__(side, side)
    def set_width(self, w): self.w = self.h = w
    def set_height(self, h): self.w = self.h = h

def stretch(r: Rectangle):
    r.set_width(5)
    r.set_height(4)
    return r.area()   # 20 for Rectangle, 16 for Square
Red flag to avoid:

Saying the design is fine because a square is mathematically a rectangle, or thinking matching signatures is enough to satisfy Liskov.

They may ask next:
  • What other signs tell you a subclass is breaking substitution?
  • Would making both classes immutable fix the problem, and why?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

15. Explain the Dependency Inversion Principle. How is it different from dependency injection?

What the interviewer is really testing:
Whether you can separate the design principle, which way dependencies point, from the technique of passing dependencies in from outside.
Answer frame:

Principle: high-level policy and low-level details both depend on an abstraction; the abstraction belongs to the high-level side.

Injection: a technique: an object receives its dependencies, often through the constructor, instead of creating them.

Relationship: injection helps you apply the principle, but injecting concrete classes doesn't achieve it.

Sample spoken answer:

"Dependency inversion says my business logic shouldn't depend on low-level details like a specific database or payment provider. Both should depend on an abstraction, and that abstraction is shaped by what the business logic needs. So an OrderService depends on a PaymentGateway interface that the order module defines, and the concrete provider class implements it. The arrow that used to point from orders down to the provider now points from the provider up to the interface; that's the inversion. Dependency injection is a technique: instead of the OrderService creating its own gateway with new, someone passes one into its constructor. Injection makes the principle easy to apply, but they aren't the same. I can inject a concrete provider class and still be tightly bound to it, and I can follow the principle with a simple factory and no framework at all."

Red flag to avoid:

Treating the principle, dependency injection and a framework's container as one and the same thing.

They may ask next:
  • Why should the interface live with the high-level module rather than with the implementation?
  • What do you lose if every class gets an interface just to satisfy this principle?
Say it in 60 seconds

Class Relationships 3 questions

Medium Technical round Fresher, Mid-level, Senior Practice question

16. What does favour composition over inheritance mean? Give me a case where inheritance was the wrong tool.

What the interviewer is really testing:
Whether you understand the costs of inheritance, tight coupling to the parent and rigid hierarchies, and can still say when inheritance is fine.
Answer frame:

Meaning: build behaviour by holding and delegating to other objects rather than extending a class.

Why: inheritance ties you to the parent's internals and fixes behaviour at compile time.

When inheritance is fine: a true is-a relationship where the child can stand in for the parent everywhere.

Sample spoken answer:

"It means that when I want to reuse behaviour, my first choice is to have an object hold another object and delegate to it, rather than extend its class. Inheritance couples a subclass to the parent's implementation, so a change in the parent can quietly break every child, and the behaviour is fixed when I write the class. A well-known case is Java's own Stack class, which extends Vector, so a stack lets you insert into the middle, which no stack should allow. Holding a list inside and exposing only push and pop would have been right. Another sign is class explosion: FlyingDuck, SwimmingDuck, FlyingSwimmingDuck. With composition I give a duck a fly behaviour and a swim behaviour and can swap them at run time. Inheritance is still fine when the child truly is a kind of parent and can replace it anywhere."

Red flag to avoid:

Saying inheritance should never be used, or being unable to name any real cost of it.

They may ask next:
  • What is the fragile base class problem?
  • How would you test a class built by composition compared to one that inherits its behaviour?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

17. What do coupling and cohesion mean, and why do we aim for low coupling and high cohesion?

What the interviewer is really testing:
Whether you can explain the two measures in plain terms and link them to how easy code is to change and test.
Answer frame:

Cohesion: how closely the things inside one class belong together.

Coupling: how much one class knows about and relies on another.

Goal: focused classes that talk through small interfaces, so a change stays local.

Sample spoken answer:

"Cohesion is about what's inside a class: do all its fields and methods serve one purpose? A ShoppingCart that adds items, removes them and totals them is cohesive. If it also sends marketing emails, cohesion drops. Coupling is about the links between classes: how much one knows about another's internals. If my checkout code reaches into the cart's private list and the product's pricing fields, it's tightly coupled, and changing either one breaks checkout. We want high cohesion because a focused class is easier to understand and test, and low coupling because then a change in one class stays inside it instead of rippling across the codebase. In practice I lower coupling by talking through small interfaces and asking objects to do things rather than pulling their data out."

Red flag to avoid:

Mixing the two up, or saying both should be as high as possible.

They may ask next:
  • Can you have zero coupling? What would that look like?
  • How can you spot tight coupling in a code review?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

18. What's the difference between association, aggregation and composition? Give me an example of each.

What the interviewer is really testing:
Whether you can tell apart the strengths of has-a relationships by ownership and lifetime, which drives real modelling decisions.
Answer frame:

Association: one object knows about or uses another; no ownership.

Aggregation: a whole-part link where the part can live on without the whole.

Composition: strong ownership; the part is created with the whole and dies with it.

Sample spoken answer:

"All three are has-a relationships; the difference is ownership and lifetime. Association is the loosest: a Doctor treats Patients, a Teacher teaches Students. They know about each other, but neither owns the other. Aggregation is a whole-part link where the part can exist on its own: a Team has Players, but if the team is dissolved, the players still exist and can join another team. Composition is strong ownership: an Order has OrderLines, and a line makes no sense without its order. If the order is deleted, its lines go with it, and nobody else holds them. In UML aggregation is a hollow diamond and composition a filled one. In code, it shows up in who creates the part, whether it's shared, and what gets deleted together."

Red flag to avoid:

Treating aggregation and composition as the same, or not mentioning the lifetime of the part.

They may ask next:
  • In a database, how would composition show up in your foreign keys or delete rules?
  • Is a Car and its Engine aggregation or composition? What decides it?
Say it in 60 seconds

Design Patterns 4 questions

Medium Technical round Mid-level, Senior Practice question

19. When is a singleton a reasonable choice, and why do so many engineers treat it as an anti-pattern?

What the interviewer is really testing:
Whether you know the pattern's real costs, hidden global state and hard testing, and prefer a single instance passed in over a globally reachable one.
Answer frame:

What it is: a class that ensures only one instance exists and offers a global way to reach it.

Fair uses: something truly shared and expensive: a connection pool, a config loaded once.

Costs: hidden dependencies, global mutable state, hard to replace in tests, thread-safety to get right.

Sample spoken answer:

"A singleton guarantees one instance and gives everyone a global way to reach it. Having only one of something is often fine: one connection pool, one config loaded at startup. The trouble is the global access. Any class can grab it without saying so in its constructor, so dependencies are hidden. If it holds mutable state, it's a global variable in disguise, shared by every thread and every test. And because callers fetch it themselves, I can't easily swap in a fake for a unit test. So what I usually do is create one instance at startup and pass it to the classes that need it. I still get one instance, but the dependency is visible and replaceable. I'd only use a classic singleton for something that holds no business state, like a logger, where those costs barely matter."

Red flag to avoid:

Reaching for a singleton whenever something is shared, or not being able to name a single downside.

They may ask next:
  • How would you unit test a class that calls a singleton directly inside its methods?
  • What can go wrong if two threads create the singleton at the same moment?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

20. What problem does the factory pattern solve, and when is a plain constructor call the better choice?

What the interviewer is really testing:
Whether you use factories to hide a real creation decision, not as ceremony around every new.
Answer frame:

Problem: callers shouldn't need to know which concrete class to build or how to build it.

Shape: one method takes input or config and returns an object behind a common type.

Skip it: when there's one concrete class and building it is simple.

Sample spoken answer:

"A factory puts the decision about which class to create in one place. Say I read a file and the extension decides whether I need a CsvParser, a JsonParser or an XmlParser. Without a factory, that if-else ends up in every caller, and each caller now depends on all three classes. With a ParserFactory, callers ask for a parser for this file and get back something of type Parser; they never see the concrete classes. It also helps when building an object takes several steps or needs config the caller shouldn't know about. But if there's only one implementation and the constructor takes two simple arguments, a factory is just extra code to read. I'd call new directly and add the factory the day a second variation actually appears."

Red flag to avoid:

Wrapping every object creation in a factory by default, or not being able to say what decision the factory is hiding.

They may ask next:
  • How is a factory method in a base class different from a separate factory class?
  • How do you add a new parser type without editing the factory every time?
Say it in 60 seconds
Medium Coding round Fresher, Mid-level Practice question

21. Walk me through the strategy pattern with a pricing or discount example. How would you add a new rule later?

What the interviewer is really testing:
Whether you can apply the pattern to a realistic problem and show that new behaviour plugs in without touching the class that uses it.
Answer frame:

Idea: pull a varying algorithm out into its own family of classes behind one interface.

Wiring: the context holds a strategy and calls it; it doesn't know which one it has.

Extending: a new rule is a new class; the context is unchanged.

Sample spoken answer:

"Strategy is for when one step of a process has several interchangeable versions. At checkout, the discount rule varies: none, a seasonal cut, a member rate. Instead of an if-else inside Checkout, I define a DiscountRule interface with one apply method and write each rule as its own small class. Checkout takes a rule in its constructor and just calls apply; it has no idea which rule it has. Adding a new promotion later means writing one new class and choosing it where Checkout is created, usually from config. Checkout and the existing rules don't change, and each rule can be unit tested alone. In languages with first-class functions I'd often just pass a function, which is the same idea with less code."

Code:
interface DiscountRule {
    long apply(long totalCents);
}

class NoDiscount implements DiscountRule {
    public long apply(long totalCents) { return totalCents; }
}

class SeasonalDiscount implements DiscountRule {
    public long apply(long totalCents) { return totalCents - totalCents / 10; }
}

class Checkout {
    private final DiscountRule rule;
    Checkout(DiscountRule rule) { this.rule = rule; }
    long finalTotal(long totalCents) { return rule.apply(totalCents); }
}
Red flag to avoid:

Keeping the if-else inside the context and calling it strategy, or not knowing where the choice of strategy is made.

They may ask next:
  • How is strategy different from simply subclassing Checkout for each discount?
  • Who decides which strategy to use, and where should that decision live?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

22. How does the observer pattern work, and what can go wrong with it in a long-running application?

What the interviewer is really testing:
Whether you know the mechanics and the practical failure modes: forgotten subscriptions, surprise ordering and flows that are hard to trace.
Answer frame:

Mechanics: a subject keeps a list of observers and notifies each when something changes.

Benefit: the subject doesn't know who is listening, so new reactions plug in freely.

Pitfalls: listeners never removed, order assumptions, one failing observer, cascades that are hard to follow.

Sample spoken answer:

"A subject, say an Order, keeps a list of observers. When its status changes it loops through the list and calls each one's update method. The email sender, the stock updater and the analytics tracker all subscribe, and the Order doesn't know any of them exist, so adding a new reaction is just one more subscriber. In a long-running app, the classic problem is forgetting to unsubscribe. The subject still holds a reference, so an old screen or object can't be garbage collected and keeps receiving events: a memory leak plus strange behaviour. Others: observers quietly relying on notification order, one observer throwing and stopping the rest from being called, and chains where one update triggers another until nobody can trace why something happened. I handle those with explicit unsubscribe on teardown, isolating failures per observer, and logging events."

Red flag to avoid:

Describing the mechanics correctly but having never thought about unsubscribing or what happens when an observer throws.

They may ask next:
  • How would you stop one slow observer from holding up all the others?
  • When would you move from in-process observers to a message queue?
Say it in 60 seconds

Object Modelling 2 questions

Hard System design round Mid-level, Senior Practice question

23. Design the class model for a parking lot. What classes would you create, and how do they relate to each other?

What the interviewer is really testing:
Whether you clarify requirements first, find the right nouns and responsibilities, and put variable rules like pricing behind their own abstraction.
Answer frame:

Clarify: floors, spot sizes, vehicle types, tickets, how fees are charged.

Core classes: ParkingLot, Level, ParkingSpot, Vehicle, Ticket, with clear ownership.

Variable rules: spot allocation and fee calculation as swappable strategies.

Edge cases: lot full, lost ticket, two cars grabbing the same spot.

Sample spoken answer:

"First I'd ask a few questions: how many levels, which vehicle types, do spot sizes matter, and is pricing hourly or flat. Assuming levels, three spot sizes and hourly fees, I'd have a ParkingLot that owns Levels, and each Level owns ParkingSpots. A spot knows its size and whether it's free. A Vehicle has a plate and a size; I'd use an enum for size rather than a subclass per vehicle, because the vehicle types don't behave differently here. When a car enters, the lot asks a SpotAllocator for a suitable free spot and creates a Ticket holding the vehicle, spot and entry time. On exit, a FeeCalculator turns the ticket into a charge. I'd keep allocation and pricing as interfaces so a nearest-spot rule or weekend rate can be swapped in. And I'd make claiming a spot safe when two entry gates try at once."

Red flag to avoid:

Jumping straight into a big inheritance tree of vehicle subclasses without asking any requirements or saying where responsibilities live.

They may ask next:
  • How would your design change if electric vehicles need charging spots?
  • Where would you put the rule that a large van can't use a compact spot?
  • How do you stop two gates from assigning the same spot at the same moment?
Say it in 60 seconds
Medium System design round Fresher, Mid-level Practice question

24. Model a library system with books, members and loans. Which classes do you need, and which class owns the borrowing rules?

What the interviewer is really testing:
Whether you spot the key modelling split, a title versus a physical copy, and put rules in a sensible place instead of a god class.
Answer frame:

Title vs copy: a Book holds shared details; each BookCopy is one physical item with its own status.

Loan: a class of its own linking a copy, a member and dates.

Rules: limits and due dates live in a policy or service, not scattered across Book and Member.

Sample spoken answer:

"The first thing I'd separate is the book from its copies. A Book is the title, author and ISBN; a BookCopy is one physical item on the shelf with its own barcode and status, available, on loan or lost. The library can own five copies of one book, and you borrow a copy, not a title. Then a Member with an id and a membership type, and a Loan that links one copy to one member with a borrow date, a due date and a return date. Loans deserve their own class because they have their own data and history. The rules, like how many books a member can hold or how long a loan lasts, I'd put in a LoanPolicy that a LibraryService checks before creating a loan. That keeps Book and Member simple and lets rules differ by membership type."

Red flag to avoid:

Treating a book and a copy as the same object, or loading every rule into one giant Library class.

They may ask next:
  • How would you add reservations when every copy of a book is out?
  • Where would you calculate late fees, and why there?
Say it in 60 seconds

Design in Practice 6 questions

Medium Behavioral round Mid-level, Senior Practice question

25. Tell me about a class hierarchy you had to untangle because inheritance got out of hand. What did you change it to?

What the interviewer is really testing:
Whether you have lived with the costs of deep inheritance and can refactor safely, step by step, with tests behind you.
Answer frame:

Situation: how deep the tree was and what pain it caused.

Change: what you pulled out into composed pieces or interfaces.

Safety: tests first, small steps, nothing big-bang.

Result: what got easier afterwards.

Sample spoken answer:

"At my last company we had a notification module where BaseNotification had grown into five levels of subclasses: EmailNotification, then ScheduledEmailNotification, then RetryingScheduledEmailNotification, and so on. Adding a retrying SMS meant copying half a branch, and a change in the base class broke three channels at once. I first wrote tests around the current behaviour for each channel. Then I pulled out the things that varied, the channel, the scheduling and the retry policy, into small objects behind interfaces, and made a single Notification class that holds one of each. I moved one channel at a time, keeping the old classes until the new path passed the same tests. At the end we had one class and a handful of small parts, and adding a new channel became a single class."

Red flag to avoid:

A story of a big-bang rewrite with no tests, or one where the new design is just a different deep hierarchy.

They may ask next:
  • How did you convince the team the refactor was worth the time?
  • What would you have done if there had been no tests to start from?
Say it in 60 seconds
Medium Behavioral round Mid-level, Senior Practice question

26. Tell me about a time you added an abstraction or a design pattern to your code and later decided it was a mistake.

What the interviewer is really testing:
Whether you can admit over-engineering and have learned when a pattern pays for itself and when it's only extra layers.
Answer frame:

What you built: the pattern and why it felt right then.

What went wrong: the cost it added with no real benefit.

What you did: how you simplified it.

Rule now: how you decide today.

Sample spoken answer:

"Early in my career I built an internal reporting tool and was keen on patterns. For exporting reports I added an Exporter interface, an abstract base exporter, a factory, and a registry that loaded exporters by name from config. We only ever had one format, CSV. For a year, every small change meant reading four files to find the one line that mattered, and a new teammate asked me why it was so complicated. I couldn't give a good answer. I collapsed it into a single CsvExporter class, which cut the code by more than half and made the bug fixes trivial. When we did later add Excel, pulling out an interface took an afternoon. My rule now is to add the abstraction when the second real case arrives, not when I imagine it might."

Red flag to avoid:

Claiming you've never over-engineered anything, or telling the story without a lesson you still use.

They may ask next:
  • How do you tell the difference between planning ahead and over-engineering?
  • Have you seen the opposite mistake, where an abstraction was added too late?
Say it in 60 seconds
Easy Behavioral round Fresher, Mid-level Practice question

27. Walk me through the main classes in a project you built, and tell me one design choice you'd make differently now.

What the interviewer is really testing:
Whether you can explain your own design clearly and look back at it critically, which shows how you'll reason about the team's code.
Answer frame:

Overview: what the project does in one line.

Main classes: three to five, with what each is responsible for.

Change now: one concrete decision you'd revisit and why.

Sample spoken answer:

"In my final-year project I built a small hospital appointment system. The main classes were Patient, Doctor, Appointment, and a Schedule that belonged to each doctor and held their free slots. An AppointmentService took a request, asked the doctor's schedule for a free slot, and created the Appointment. Notifications went through a separate Notifier class so the booking logic didn't know about email. What I'd change now: I put the cancellation rules, like no cancelling within two hours, directly inside the Appointment class with a bunch of if statements, and every new rule meant editing it. Today I'd pull those into a small CancellationPolicy object, so the rules could differ by department and be tested on their own without building whole appointments."

Red flag to avoid:

Describing screens and database tables only, with no classes or responsibilities, or claiming there is nothing you'd change.

They may ask next:
  • Why did you give each doctor a Schedule instead of storing free slots on the Doctor directly?
  • How did you test the booking logic?
Say it in 60 seconds
Medium Situational round Mid-level, Senior Practice question

28. In a pull request, a teammate adds an interface, a factory and a strategy for a feature that has exactly one implementation. How do you respond?

What the interviewer is really testing:
Whether you know when not to use patterns and can push back on design in review respectfully, with reasons rather than taste.
Answer frame:

Ask first: is a second implementation actually planned, or is this a guess?

Cost: more files and indirection for every reader, today, for a benefit that may never come.

Tone: suggest the simpler version, explain how easy it is to add the layers later.

Sample spoken answer:

"I'd start by asking, not ruling. Maybe there's a second implementation on the roadmap I don't know about. If there is, and it's soon, the design might be right. If it's a just-in-case, I'd explain the cost in the review: three extra types and a factory that every reader has to click through, to reach one class that does the work. I'd suggest shipping the single concrete class and point out that extracting an interface later, when a real second case shows up, is a quick and safe refactor. I'd keep it about the code, not about their skills, and say what they got right, like keeping the class small and testable. If they still feel strongly and it's not harmful, I'd let it go rather than block the release over style."

Red flag to avoid:

Approving without comment to avoid friction, or rejecting the change as over-engineered without asking why it was built that way.

They may ask next:
  • What if the teammate is more senior than you?
  • Are there cases where adding the interface up front is worth it even with one implementation?
Say it in 60 seconds
Medium Situational round Mid-level, Senior Practice question

29. To hit a deadline, a teammate wants a new subclass that throws a not-supported error for half of its parent's methods. What do you say?

What the interviewer is really testing:
Whether you recognise a Liskov and interface design problem in a real setting and can offer a fix that still fits the deadline.
Answer frame:

Name the risk: any code holding the parent type can now crash at run time.

Root cause: the parent promises more than every child can do.

Options: a narrower interface, a separate class, or a clearly tracked short-term exception.

Sample spoken answer:

"I'd explain the risk in concrete terms: every piece of code that holds the parent type assumes all its methods work. With this subclass, some of them will blow up at run time, and nothing at compile time will warn anyone. It's a sign the parent is promising too much. So I'd look for the smallest fix that still fits the deadline. Often that's splitting out a narrower interface with just the methods the new class really supports, and having the callers that need it depend on that instead. If that's too big for now, I'd suggest making it a separate class that doesn't inherit at all. If we truly must ship it this way, I'd want it documented, kept away from generic code paths, and a ticket to fix it right after the release."

Red flag to avoid:

Saying it's fine as long as the new methods throw clear errors, or blocking the deadline without offering any alternative.

They may ask next:
  • How would you find every caller that could receive this new subclass?
  • Are there standard library examples where this pattern exists, and why do people complain about them?
Say it in 60 seconds
Hard Situational round Mid-level, Senior Practice question

30. You need to add a feature to a three-thousand-line class that half the codebase depends on, and it has very few tests. How do you go about it?

What the interviewer is really testing:
Whether you can deliver safely inside legacy object-oriented code: protect behaviour first, change in small steps, and improve the design only as far as the task needs.
Answer frame:

Protect: write characterization tests around the part you'll touch.

Isolate: extract the area you need into a new, small class behind the old method.

Add: build the feature in the new class, with proper tests.

Limit scope: no rewrite; leave it a little better, not perfect.

Sample spoken answer:

"I wouldn't try to rewrite it, and I wouldn't just add another two hundred lines either. First I'd find the exact methods my feature touches and write characterization tests around them: tests that record what the code does today, even the odd parts, so I'll know if I change it by accident. Then I'd extract the logic I need into a new, focused class, and have the old methods delegate to it, so every caller still works unchanged. My feature goes into the new class, where it's small enough to test properly. If the class creates its own dependencies, I'd add a way to pass them in so the tests don't hit a real database. I'd keep each step a separate small commit, and I'd tell the team what I extracted so the next person can keep going the same way."

Red flag to avoid:

Proposing a full rewrite before the feature, or adding the change straight into the big class with no tests at all.

They may ask next:
  • How do you write tests for code whose correct behaviour nobody can tell you?
  • What would make you stop and argue for a bigger rewrite instead?
Say it in 60 seconds
Were you asked something else? Share it A person checks every question before it goes on the site. No name is shown.
For the call itself

The questions above are the prep. The call has ten more.

ClapAssist is an AI interview assistant for Mac and Windows. It listens to the interview on your computer and shows you what to say, in short lines you can read while you talk. Your resume and notes are never stored on our servers. It stays out of screen share on every plan; only you can see it.

Download ClapAssist with 10 free minutes
Mac and Windows · Stays out of screen share · No card