Skip to content

OOP and Design Basics

~12 min

In short

Object-oriented questions usually start with definitions and then move to a small design task: model a real system as classes, say what each class is responsible for, and explain the trade-offs. Interviewers care more about clear responsibilities and sensible relationships than about naming many design patterns. Practise the parking lot exercise below until you can do it without looking anything up.

Checklist

  • [ ] What is the difference between a class and an object?
  • [ ] Explain encapsulation with an example.
  • [ ] What is abstraction? How is it different from encapsulation?
  • [ ] What is inheritance? When is it the wrong tool?
  • [ ] What is polymorphism? Compare compile-time and run-time polymorphism.
  • [ ] When would you use an interface, and when an abstract class?
  • [ ] Composition or inheritance: which would you prefer, and why?
  • [ ] Explain the Single Responsibility Principle with an example.
  • [ ] Explain the Open/Closed Principle with an example.
  • [ ] Explain the Liskov Substitution Principle. Why is Square-Rectangle a common trap?
  • [ ] Explain the Interface Segregation Principle.
  • [ ] Explain the Dependency Inversion Principle.
  • [ ] What is coupling, and what is cohesion? Which do you want more of?
  • [ ] What is the difference between method overloading and overriding?
  • [ ] What does this or self refer to?
  • [ ] What is a constructor? When would you use a factory instead?
  • [ ] Name a design pattern you have used, and the problem it solved.
  • [ ] Design a parking lot. Which classes do you create?
  • [ ] How would you test one class in isolation?
  • [ ] What would you ask the interviewer before you start designing?

Key ideas

Four pillars. Encapsulation keeps data behind methods that enforce rules. A bank account that refuses a withdrawal larger than its balance is an example. Abstraction exposes only the operations a user needs and hides how they work. Encapsulation hides data; abstraction hides complexity. Inheritance lets a subclass reuse and specialise a parent, and models an "is-a" relationship, but it couples the subclass tightly to the parent. Polymorphism lets code call the same operation on different types. Overloading (same name, different parameters) is resolved at compile time in statically typed languages. Overriding (a subclass replacing a parent's method) is resolved at run time through dynamic dispatch.

Interfaces and abstract classes. An interface declares what a type can do. An abstract class can also hold shared state and default behaviour. Language details differ: Java and C# have both, while Python uses abstract base classes and duck typing. Use an interface when unrelated classes must share a capability.

Composition. Building a class out of objects it holds ("has-a") is often more flexible than inheriting. A Car has an Engine rather than being one, so you can swap the engine without touching the rest of the car. This is a judgement call, not a rule.

SOLID, at a basic level.

  • Single Responsibility: a class should have one reason to change. A class that parses a file and also sends emails has two.
  • Open/Closed: add new behaviour by adding code rather than editing working code. A new discount type should be a new class.
  • Liskov Substitution: a subtype must work wherever its parent is expected. A Square that breaks the width and height rules of a Rectangle is the classic violation.
  • Interface Segregation: several small interfaces beat one large one. Clients should not depend on methods they never call.
  • Dependency Inversion: depend on abstractions, and pass dependencies in. High-level code should not create its own database connection.

Coupling and cohesion. Cohesion measures how closely the responsibilities inside a class belong together; you want high cohesion. Coupling measures how much one class depends on another; you want low coupling. Most SOLID advice is a way of getting both.

Patterns to know by name. Factory creates objects without the caller naming the concrete class. Strategy swaps an algorithm at run time. Observer notifies subscribers when something changes. Learn what problem each solves, and do not force a pattern into code that does not need it.

LLD exercise: parking lot

Ask first. How many floors and spot sizes? Which vehicle types? How is payment taken? Then sketch these classes:

  • ParkingLot owns the levels. park(vehicle) returns a Ticket. unpark(ticket) returns the fee.
  • Level holds its spots and reports how many are free.
  • ParkingSpot has an id, a size (compact, regular or large) and an occupied flag.
  • Vehicle is abstract, with Bike, Car and Truck subclasses. Each knows its size.
  • Ticket holds the vehicle, the spot and the entry time.
  • FeeStrategy is an interface, with an hourly implementation. New pricing means a new class.
  • SpotAllocator is an interface that picks a free spot of the right size.

Check your design. A truck should never be given a compact spot. Adding a new vehicle type should touch the vehicle hierarchy and the size rule, not the whole lot. Concurrent entry gates are a good follow-up topic, but raise them after the basic design works.

Try this

Write the parking lot classes in any language, in under 150 lines. Then write three tests: park a bike, park a car and a truck, and confirm the truck is refused a compact spot. Write one paragraph on what you would change if pricing became time-of-day based.

Sources