Knowledge Bank
  • My GitBook
  • Miscellaneous
  • Project
    • Rider and Intellij
    • Code
    • Frontend
      • Condition
      • AddConditionModalDialog
    • Backend
    • e2e
      • fragments
  • JAVASCRIPT
    • Promise
    • Destructuring
    • Spread Syntax and Rest Parameters
    • Typescript
      • Examples of Types
      • React Typescript
    • This
    • Dot Notation vs Bracket Notation
    • Shallow vs Deep Clone
    • New ES Edition
  • C#
    • Project Note
    • Basic
    • Shortcut and Debugging
  • Programming Paradigms
    • SOLID Principles
    • Object Oriented Programming (OOP)
      • Evolution of OOP (Procedural to OOP)
      • Instantiation
      • 4 Pillars of OOP
      • Extra
    • Functional Programming (FP)
      • Idempotent
      • Imperative vs Declarative
      • Immutability
      • High Order Function and Closure
      • Currying
      • Partial Application
      • Memoization and Caching
      • Compose and Pipe
      • Extra
      • Example of FP
    • OOP vs FP
      • Composition vs Inheritance
  • DATA STRUCTURE
    • Big O
    • Data Structure
    • Array
    • Hash Table
    • Linked List
    • Queue and Stack
    • Tree
      • Binary Heap
      • Trie
    • Graph
      • Example of Graph
  • React-Redux
    • MobX
    • Best Practices
  • Algorithms
    • Recursion
      • Examples of Recursion
    • Sorting
    • Searching and Traversal
    • Dynamic Programming
  • REFACTORING
    • Clean Code
      • Formatting
      • Error Handling
      • Concurrency
      • Testing
      • SOLID Principles
      • Classes
      • Objects and Data Structures
      • Variables
      • Functions
    • Code Smells
      • Long Function
      • Duplicate Code
      • Loops
      • Double Negative
      • Christmas Tree Code
      • Complex Condition
      • Primitive Obsession
      • Speculative Generality
      • God Class
      • Long Parameter List
  • Junior to Senior
    • AWS
      • Lambda
    • Session + Authentication
    • Redis
    • Kubernetes
      • Networking
      • Services
      • Deployment
      • Replica Set
      • YAML
      • pod-definition.yml
      • Kubectl
      • Pods
      • Fundamentals
    • Docker
      • Operating System - Extra
      • Dockerfile - Docker Image
      • Docker Storage
      • Docker Network
      • Docker Registry
      • Docker Command
      • Docker Compose
      • Docker Compose - Postgres
    • Security
      • Logging
      • HTTPS, Cross-Site-Scripting (XSS) and Cross-Site-Request-Forgery (CSRF)
      • 3rd Party Library
      • Injection
      • Code Secret, Secure Header, Access Control, Data Management, Authentication
    • CI/CD
    • SPA vs Server-Side Rendering
    • Performance
      • Optimized Code
      • Critical Render Path
      • Backend Optimization
      • Minimized Files and Images
      • Minimized Delivery
  • SECURITY
    • Encryption
    • SSH
  • Command
  • Cheatsheet
    • NPM
    • GIT
  • Writing Template
    • Guide
    • API
    • ChangeLog
    • FAQ
  • Linux
Powered by GitBook
On this page

Was this helpful?

  1. Programming Paradigms
  2. OOP vs FP

Composition vs Inheritance

PreviousOOP vs FPNextBig O

Last updated 5 years ago

Was this helpful?

Inheritance is when you design your types around what they are. Via inheritance. You can define the logic in a parent class and all children class can inherit it and reuse it.

Composition is when you design your types around what they do.Via Composition. You can define the logic in a helper class and then whoever need that function can keep a reference to that helper and reuse it.

Imagine we have two super-class: Robot and Animal. (Left-Side) How do we create Murder Robot Dog that can drive, kill, bark and not poop? (Right-Side) One way is to derive sub-class from Robot, but it will have unnecessary property and methods inherited (Banana-Gorilla problem). Inheritance have hierarchy problem and this will become issue when circumstance change and there is shift in the hierarchy.

// Composition to the rescue by separating the data and methods
const learnAttack = character => ({
  attack: () => console.log(`${character.name} attacked`)
});

const learnSleep = character => {
  return {
    sleep: () =>
      console.log(`${character.name} fall asleep with ${character.weapon}`)
  };
};

const learnIntroduce = character => {
  return {
    introduce: () =>
      console.log(`Hi, my name is ${character.name}. I am ${character.type}`)
  };
};

function LazyElf(name, type, weapon) {
  let lazyElf = {
    name,
    type,
    weapon
  };
  return Object.assign(
    {},
    lazyElf,
    learnIntroduce(lazyElf),
    learnSleep(lazyElf)
  );
}

function FitElf(name, type, weapon) {
  let fitElf = {
    name,
    type,
    weapon
  };
  return Object.assign({}, fitElf, learnAttack(fitElf), learnIntroduce(fitElf));
}

const leroy = LazyElf("Leroy", "lazy elf", "bow");
const ben = FitElf("Ben", "fit elf", "stone");

// learnAttack(leroy).attack() //Not part of Leroy's method
leroy.sleep();
leroy.introduce();
console.log(leroy);

// learnSleep(ben).sleep() //Not part of Ben's method
ben.attack();
ben.introduce();
console.log(ben);

You should favor composition over inheritance because inheritance encourages you to predict the future. You build the objects very early on in the project. And you are most likely going to make big design mistakes while doing that. Because humans cannot predict the future. It's just better to use composition from the start. It's more flexible, it's more powerful, and it's really easy to do. Inheritance has problem of tight coupling where if you change something on a class, you have to make sure that it doesn't break anything with its sub classes.

However, that does not mean we should always avoid Inheritance. That's still a valid technique in OOP. Here is a rule of thumb to help you decide when to use Inheritance and when to use Composition.

  • You should declare a class B inherits from class A only when there is a true is-a relationship between the two classes.

    • This means, don't let a class inherit another parent class just because you need to reuse some logic in parent class. Code reuse via composition could be a better choice here.

  • You should compose class B with class A (i.e. keeping a reference to class A in class B) when there is a has-a relationship between the two classes.