The Four Pillars of OOP
Fast recall
Quick revision
Core answer
Whether you can name the four pillars and map them to Ruby (encapsulation: private/attr_*; inheritance: <; polymorphism: duck typing/override).
Thinking Ruby needs formal interfaces for polymorphism (it uses duck typing), or over-using inheritance where a module fits.
Four pillars: Encapsulation (private/attr_*), Abstraction (classes), Inheritance (<), Polymorphism (duck typing/override). Ruby does all four; polymorphism uses duck typing, not formal interfaces.
Interview-ready guide
Interview answer
The four OOP pillars describe ways to organise objects and their responsibilities. Encapsulation keeps state changes behind a controlled public boundary; in Ruby that often means instance variables plus public action methods and private helpers.
Abstraction gives callers a simpler operation than the steps required internally. account.withdraw(50) expresses the goal while the Account handles validation and balance changes. The caller does not manipulate @balance or repeat the account's rules.
Inheritance creates a subtype with class Child < Parent. A subclass receives behaviour through method lookup, can override it, and can call the next implementation with super. It is appropriate only when the child can safely be used wherever the parent is expected.
Polymorphism means one message works across different implementations. For example, EmailNotifier and SmsNotifier can both implement deliver(message), and calling code depends on that behaviour rather than branching on class names. Ruby's duck typing makes a common base class optional.
These ideas work together but solve different problems: protect valid state, present a clear interface, reuse a true subtype contract, and vary behaviour behind the same message. A practical design starts with a small public contract, keeps its rules inside the responsible object, and introduces variation only where the application needs it. Composition is often simpler than inheritance when only one capability needs to be reused.
The Four Pillars of OOP
Direct Answer
The four commonly taught OOP pillars are encapsulation, abstraction, inheritance, and polymorphism. In Ruby, encapsulation protects an object's state behind public methods and visibility; abstraction exposes a small useful interface while hiding steps; inheritance lets a subclass specialise an ancestor's contract; and polymorphism lets different objects respond to the same message in their own way. They are design tools, not a requirement to build deep class hierarchies.
Deep Dive & Architecture
Encapsulation is about authority, not hiding every field. The object should be the one place allowed to move its state between valid conditions. A reader may expose balance safely, while a general balance writer would let every caller bypass withdrawal rules.
Abstraction chooses the vocabulary of that boundary. A good public method names an outcome the caller understands and keeps storage, calculation order, and collaborators replaceable. An abstraction leaks when callers must know those internal steps to use it correctly.
Inheritance affects identity and method lookup. The child inherits the parent's promises as well as its implementation. If the child rejects valid parent inputs or changes the meaning of results, reuse has broken substitutability even if the syntax is legal.
Polymorphism removes conditionals from the caller by moving variation to receivers. A small message contract can be implemented by unrelated classes, test doubles, or adapters. Tests should verify the shared semantics, because matching method names alone do not guarantee matching behaviour.
Code Example
class Account
attr_reader :balance
def initialize(balance)
@balance = balance
end
def withdraw(amount)
raise ArgumentError, 'invalid amount' unless amount.positive?
raise 'insufficient funds' if amount > @balance
@balance -= amount
end
end
class EmailNotifier
def deliver(message)
"email: #{message}"
end
end
class SmsNotifier
def deliver(message)
"sms: #{message}"
end
end
def notify(notifier, message)
notifier.deliver(message) # polymorphic message
end
Common Mistakes & Pitfalls
Thinking Ruby needs formal interfaces for polymorphism (it uses duck typing), or over-using inheritance where a module fits.
Check your understanding
Answer these without looking back at the article.
- How are encapsulation and abstraction different?
- When does inheritance violate substitutability?
- How does Ruby support polymorphism without a common superclass?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.