GoF 23 + JS Patterns · 27 Total · Interview Reference

Design Pat terns

// Simple examples · Complete reference · Interview ready

🟦

Creational Patterns

5 patterns
01 Singleton CREATIONAL

🎯 PROBLEM IT SOLVES

When you need exactly one object in your entire app — like app settings or the logged-in user. Creating multiple instances would cause conflicts.

💡 WHEN TO USE

  • App settings (theme, language)
  • Currently logged-in user
  • Logger / error tracking
  • Database connection pool
❌ Problem — two different instances!
// We made two separate user config objects
const user1 = { name: "Ali", theme: "dark"  };
const user2 = { name: "Ali", theme: "light" };
// Which one is the real config? 🤔
✅ Singleton — always one instance
const CurrentUser = (function() {
  let instance;
  return {
    getInstance() {
      if (!instance) {
        instance = { name: "Ali", theme: "dark" };
      }
      return instance;
    }
  };
})();

const a = CurrentUser.getInstance();
const b = CurrentUser.getInstance();
a.theme = "light";
console.log(b.theme); // "light" ← same object ✅
// INTERVIEW QUESTIONS
02 Factory Method CREATIONAL

🎯 PROBLEM IT SOLVES

Instead of writing 'new' everywhere, you tell the factory 'give me a user of this type' and it handles everything. Your code never needs to know the details.

💡 WHEN TO USE

  • Different user types (Admin / Guest / Member)
  • Different payment methods (Card / Wallet / Cash)
  • Different notifications (Email / SMS)
❌ Problem — if/else everywhere
// Want to add a new type? Must edit everywhere 😩
function createUser(type) {
  if (type === "admin")  return new Admin();
  if (type === "guest")  return new Guest();
  // Must come here every time you add a new type
}
✅ Factory — flexible and extensible
class AdminUser  { greet() { return "Hi Admin 👑";  } }
class GuestUser  { greet() { return "Hi Guest 👤";  } }
class MemberUser { greet() { return "Hi Member ⭐"; } }

function UserFactory(type) {
  const users = {
    admin:  AdminUser,
    guest:  GuestUser,
    member: MemberUser
  };
  return new users[type]();
}

const user = UserFactory("admin");
user.greet(); // "Hi Admin 👑" ✅
// INTERVIEW QUESTIONS
03 Abstract Factory CREATIONAL

🎯 PROBLEM IT SOLVES

When creating a group of objects that must match each other — like a user's profile page where the button, card, and badge must all share the same theme.

💡 WHEN TO USE

  • Dark / Light theme components
  • Arabic / English UI sets
  • Mobile / Desktop layouts
❌ Problem — mismatched components!
// Dark button with Light card = looks wrong 😬
const btn  = new DarkButton();
const card = new LightCard(); // ❌ mismatch!
✅ Abstract Factory — matching family
class DarkTheme {
  button() { return "🖤 Dark Button"; }
  card()   { return "🖤 Dark Card";   }
}
class LightTheme {
  button() { return "🤍 Light Button"; }
  card()   { return "🤍 Light Card";   }
}

function renderProfile(theme) {
  console.log(theme.button()); // always consistent ✅
  console.log(theme.card());
}

renderProfile(new DarkTheme()); // everything is dark ✅
// INTERVIEW QUESTIONS
04 Builder CREATIONAL

🎯 PROBLEM IT SOLVES

When creating an object with many optional properties — like a user profile. Instead of sending 10 parameters to the constructor, you build it step by step.

💡 WHEN TO USE

  • Build User Profile step by step
  • Configure search filters
  • Build an email message
❌ Problem — too many confusing parameters
// What does each parameter mean? 😵
new User("Ali", "ali@email.com", 25, true, false, "Cairo");
✅ Builder — readable step-by-step
class UserBuilder {
  constructor(name) { this.user = { name }; }
  setEmail(e)  { this.user.email = e;    return this; }
  setAge(a)    { this.user.age = a;      return this; }
  setCity(c)   { this.user.city = c;     return this; }
  setAdmin()   { this.user.isAdmin=true; return this; }
  build()      { return this.user; }
}

const user = new UserBuilder("Ali")
  .setEmail("ali@email.com")
  .setAge(25)
  .setCity("Cairo")
  .setAdmin()
  .build();
// Crystal clear! ✅
// INTERVIEW QUESTIONS
05 Prototype CREATIONAL

🎯 PROBLEM IT SOLVES

When you have an existing user and want a copy with minor changes — instead of rebuilding from scratch, just clone it and change what's different.

💡 WHEN TO USE

  • Copy user settings for a new user
  • Duplicate profile
  • Template accounts
❌ Problem — repeating same data
// Ali and Ahmed have almost the same settings 😩
const ali   = { theme:"dark", lang:"ar", role:"user" };
const ahmed = { theme:"dark", lang:"ar", role:"admin" };
✅ Prototype — clone and change what's needed
const defaultUser = {
  theme: "dark",
  lang:  "ar",
  role:  "user",
  clone() { return { ...this }; }
};

const ali   = defaultUser.clone();
const ahmed = defaultUser.clone();
ahmed.role = "admin"; // Change only what you need ✅

// Or with Object.create
const omar = Object.create(defaultUser);
omar.name = "Omar"; // inherits everything from defaultUser ✅
// INTERVIEW QUESTIONS
🟩

Structural Patterns

7 patterns
06 Adapter STRUCTURAL

🎯 PROBLEM IT SOLVES

You have an old API that returns user data in one shape, and your new code expects a different shape. Adapter translates between them without changing either side.

💡 WHEN TO USE

  • Connect old API to new code
  • Transform response shape
  • Use a library without modifying it
❌ Problem — two different shapes
// Old API returns this
const oldUser = { full_name: "Ali Ahmed", usr_age: 25 };

// Your new code expects this
// { name: "Ali Ahmed", age: 25 } ← won't work! 😩
✅ Adapter — translate between shapes
function UserAdapter(oldUser) {
  return {
    name: oldUser.full_name,
    age:  oldUser.usr_age
  };
}

const oldUser = { full_name: "Ali Ahmed", usr_age: 25 };
const user    = UserAdapter(oldUser);
console.log(user.name); // "Ali Ahmed" ✅
console.log(user.age);  // 25 ✅
// INTERVIEW QUESTIONS
07 Bridge STRUCTURAL

🎯 PROBLEM IT SOLVES

You have User Notifications — can be sent via Email or SMS, and can be Alert or Reminder types. Instead of one class per combination, separate them.

💡 WHEN TO USE

  • Notifications with different types and channels
  • Export files in different formats
  • Avoid N×M class explosion
❌ Problem — class per combination
// EmailAlert, SMSAlert, EmailReminder, SMSReminder... 😩
class EmailAlert    {}
class SMSAlert      {}
class EmailReminder {} // Grows endlessly!
✅ Bridge — separate type from channel
// Channel (implementation)
const Email = { send(msg) { console.log("📧 Email: "+msg); } };
const SMS   = { send(msg) { console.log("📱 SMS: "+msg);   } };

// Type (abstraction)
class Alert {
  constructor(sender) { this.sender = sender; }
  notify(user) { this.sender.send("🚨 Alert for: "+user); }
}
class Reminder {
  constructor(sender) { this.sender = sender; }
  notify(user) { this.sender.send("⏰ Reminder for: "+user); }
}

new Alert(Email).notify("Ali");    // 📧 Email Alert ✅
new Reminder(SMS).notify("Ali"); // 📱 SMS Reminder ✅
// INTERVIEW QUESTIONS
08 Composite STRUCTURAL

🎯 PROBLEM IT SOLVES

A user has individual permissions and permission groups. When checking access, you should handle both the same way without distinguishing.

💡 WHEN TO USE

  • Permission system (user / group)
  • Menu with submenus
  • Folder containing files and subfolders
✅ Composite — uniform interface
// Individual permission
class Permission {
  constructor(name) { this.name = name; }
  show() { console.log("  🔑 " + this.name); }
}

// Group of permissions
class PermissionGroup {
  constructor(name) { this.name=name; this.items=[]; }
  add(p) { this.items.push(p); return this; }
  show() {
    console.log("📁 " + this.name);
    this.items.forEach(p => p.show());
  }
}

const admin = new PermissionGroup("Admin")
  .add(new Permission("read"))
  .add(new Permission("write"))
  .add(new Permission("delete"));
admin.show(); // displays all permissions ✅
// INTERVIEW QUESTIONS
09 Decorator STRUCTURAL

🎯 PROBLEM IT SOLVES

Plain User → add Premium → add Verified. Instead of a new class for each combination, wrap the object and stack features on top.

💡 WHEN TO USE

  • Add badges to user (Verified, Premium)
  • Express middleware pipeline
  • Add features without modifying the class
❌ Problem — too many classes
// PremiumUser, VerifiedUser, PremiumVerifiedUser... 😩
class PremiumVerifiedUser extends User { }
✅ Decorator — wrap and extend
class User {
  constructor(name) { this.name = name; }
  getInfo() { return this.name; }
}

class PremiumDecorator {
  constructor(user) { this.user = user; }
  getInfo() { return this.user.getInfo() + " ⭐"; }
}
class VerifiedDecorator {
  constructor(user) { this.user = user; }
  getInfo() { return this.user.getInfo() + " ✅"; }
}

let user = new User("Ali");
user = new PremiumDecorator(user);
user = new VerifiedDecorator(user);
user.getInfo(); // "Ali ⭐ ✅" ✅
// INTERVIEW QUESTIONS
10 Facade STRUCTURAL

🎯 PROBLEM IT SOLVES

When a user registers, many things happen behind the scenes: save to DB, send email, create session. Facade puts all that behind one simple call.

💡 WHEN TO USE

  • User registration / login flow
  • Checkout process
  • Simplify complex APIs
❌ Problem — client manages everything
// All this inside the component?! 😩
db.saveUser(user);
email.sendWelcome(user);
session.create(user);
logger.log("registered");
✅ Facade — one call does everything
class AuthFacade {
  register(userData) {
    db.saveUser(userData);
    email.sendWelcome(userData.email);
    session.create(userData.id);
    logger.log("User registered: " + userData.name);
    return "✅ Welcome!";
  }
}

const auth = new AuthFacade();
auth.register({ name: "Ali", email: "ali@x.com" });
// Simple and clean ✅
// INTERVIEW QUESTIONS
11 Flyweight STRUCTURAL

🎯 PROBLEM IT SOLVES

You have a million users and they all share the same country data. Instead of duplicating that data a million times, share one object between them all.

💡 WHEN TO USE

  • Country/City data shared between users
  • Shared avatars or icons
  • When memory matters
❌ Problem — duplicating data
// Every user stores the same country data 😩
const users = [
  { name:"Ali",   country: { name:"Egypt", code:"EG", flag:"🇪🇬" } },
  { name:"Ahmed", country: { name:"Egypt", code:"EG", flag:"🇪🇬" } },
  // Same object duplicated a million times 😩
];
✅ Flyweight — share the shared data
const CountryPool = {};
function getCountry(code) {
  if (!CountryPool[code]) {
    CountryPool[code] = { name: "Egypt", code, flag: "🇪🇬" };
  }
  return CountryPool[code]; // same reference ✅
}

const ali   = { name: "Ali",   country: getCountry("EG") };
const ahmed = { name: "Ahmed", country: getCountry("EG") };
console.log(ali.country === ahmed.country); // true ✅ exact same object
// INTERVIEW QUESTIONS
12 Proxy STRUCTURAL

🎯 PROBLEM IT SOLVES

Before reaching user data, the Proxy checks: do you have permission? It also caches results so you don't hit the DB every time.

💡 WHEN TO USE

  • Access control on user data
  • Caching user profiles
  • Logging requests
❌ Problem — every request hits the DB
// Every getUser() call makes a DB query 😩
function getUser(id) {
  return db.query(`SELECT * FROM users WHERE id=${id}`);
}
✅ Proxy — cache + access control
const UserProxy = {
  cache: {},
  getUser(id, requester) {
    // 1. Access Control
    if (!requester.isAdmin && requester.id !== id) {
      return "❌ Access Denied";
    }
    // 2. Cache
    if (this.cache[id]) {
      console.log("📦 From cache");
      return this.cache[id];
    }
    this.cache[id] = db.query(id);
    return this.cache[id];
  }
};
// Same interface, but smarter ✅
// INTERVIEW QUESTIONS
🟨

Behavioral Patterns

11 patterns
13 Observer BEHAVIORAL

🎯 PROBLEM IT SOLVES

When the user profile changes, you want the dashboard, notifications, and header to all update automatically — without each part knowing about the others.

💡 WHEN TO USE

  • User profile update → notify all components
  • Chat messages (real-time)
  • DOM events (addEventListener)
  • State management (Redux)
❌ Problem — tight coupling
// Must know and call every component manually 😩
function updateProfile(user) {
  dashboard.refresh(user);
  header.update(user);
  notifications.push(user);
}
✅ Observer — subscribe and be notified
class UserStore {
  constructor() { this.listeners = []; }
  subscribe(fn) { this.listeners.push(fn); }
  updateProfile(data) {
    // notifies all subscribers 🔔
    this.listeners.forEach(fn => fn(data));
  }
}

const store = new UserStore();
store.subscribe(u => console.log("Header: "    + u.name));
store.subscribe(u => console.log("Dashboard: " + u.name));
store.updateProfile({ name: "Ali Updated" }); // both notified ✅
// INTERVIEW QUESTIONS
14 Strategy BEHAVIORAL

🎯 PROBLEM IT SOLVES

A user wants to log in using Email, Google, or Facebook. Instead of a giant if/else, each method becomes an independent strategy.

💡 WHEN TO USE

  • Login strategies (Email/Google/Facebook)
  • Different payment methods
  • Sorting algorithms
❌ Problem — giant if/else
function login(method, data) {
  if      (method === "email")    { /* ... */ }
  else if (method === "google")   { /* ... */ }
  else if (method === "facebook") { /* ... */ }
  // Add Apple login? Must edit this function 😩
}
✅ Strategy — plug and play
const EmailLogin    = { auth(d) { return "📧 Email: "    +d.email; } };
const GoogleLogin   = { auth(d) { return "🔵 Google: "   +d.token; } };
const FacebookLogin = { auth(d) { return "🔷 Facebook: " +d.token; } };

class AuthService {
  constructor(strategy) { this.strategy = strategy; }
  setStrategy(s) { this.strategy = s; }
  login(data) { return this.strategy.auth(data); }
}

const auth = new AuthService(EmailLogin);
auth.login({ email: "ali@x.com" }); // 📧 Email ✅
auth.setStrategy(GoogleLogin);
auth.login({ token: "abc" });          // 🔵 Google ✅
// INTERVIEW QUESTIONS
15 Command BEHAVIORAL

🎯 PROBLEM IT SOLVES

User changed their name — you want undo to restore the old name. Command saves every action as an object with execute() and undo().

💡 WHEN TO USE

  • Undo/Redo for profile editing
  • Save edit history
  • Queue of actions
✅ Command — every action is undoable
class UpdateNameCommand {
  constructor(user, newName) {
    this.user    = user;
    this.newName = newName;
    this.oldName = user.name; // save old value for undo
  }
  execute() { this.user.name = this.newName; }
  undo()    { this.user.name = this.oldName; }
}

const user    = { name: "Ali" };
const history = [];

const cmd = new UpdateNameCommand(user, "Ahmed");
cmd.execute(); history.push(cmd);
console.log(user.name); // "Ahmed"

history.pop().undo();
console.log(user.name); // "Ali" ← restored ✅
// INTERVIEW QUESTIONS
16 Iterator BEHAVIORAL

🎯 PROBLEM IT SOLVES

You have a Users Collection that might be an array, linked list, or paginated API. Iterator gives you a consistent way to loop without knowing the internal structure.

💡 WHEN TO USE

  • Paginated users list
  • Custom collection traversal
  • JS for...of on custom objects
✅ Iterator — consistent loop interface
class UserCollection {
  constructor() { this.users = []; }
  add(u) { this.users.push(u); }

  [Symbol.iterator]() {
    let i = 0;
    const users = this.users;
    return {
      next() {
        return i < users.length
          ? { value: users[i++], done: false }
          : { done: true };
      }
    };
  }
}

const list = new UserCollection();
list.add({ name: "Ali"   });
list.add({ name: "Ahmed" });

for (const user of list) {
  console.log(user.name); // Ali, Ahmed ✅
}
// INTERVIEW QUESTIONS
17 Mediator BEHAVIORAL

🎯 PROBLEM IT SOLVES

In a chat, every user needs to talk to every other user — chaos! Instead, everything goes through the ChatRoom which distributes messages.

💡 WHEN TO USE

  • Chat room / group messaging
  • Event bus between components
  • Air traffic control
✅ Mediator — ChatRoom is the hub
class ChatRoom {
  constructor() { this.users = []; }
  join(user) { this.users.push(user); user.room = this; }
  send(msg, sender) {
    this.users
      .filter(u => u !== sender)
      .forEach(u => u.receive(`${sender.name}: ${msg}`));
  }
}

class User {
  constructor(name) { this.name = name; }
  send(msg)    { this.room.send(msg, this); }
  receive(msg) { console.log("📩 " + msg); }
}

const room = new ChatRoom();
const ali   = new User("Ali");
const ahmed = new User("Ahmed");
room.join(ali); room.join(ahmed);
ali.send("Hello everyone!"); // 📩 Ali: Hello everyone! ✅
// INTERVIEW QUESTIONS
18 Memento BEHAVIORAL

🎯 PROBLEM IT SOLVES

A user edits their profile — you want them to be able to restore any previous version. Memento saves snapshots of the state.

💡 WHEN TO USE

  • Profile edit history
  • Form autosave / draft
  • Game save states
  • Ctrl+Z undo
✅ Memento — save & restore profile
class UserProfile {
  constructor(name, bio) { this.name=name; this.bio=bio; }
  save()    { return { name:this.name, bio:this.bio }; }
  restore(s){ this.name=s.name; this.bio=s.bio; }
}

const profile  = new UserProfile("Ali", "Developer");
const snapshots = [];

snapshots.push(profile.save()); // save before editing

profile.name = "Ali Ahmed";
profile.bio  = "Senior Developer";
console.log(profile.name); // "Ali Ahmed"

profile.restore(snapshots.pop());
console.log(profile.name); // "Ali" ← restored ✅
// INTERVIEW QUESTIONS
19 State BEHAVIORAL

🎯 PROBLEM IT SOLVES

A user account has states: Active, Banned, Pending. When they take an action, the behavior changes based on the current state — no if/else needed.

💡 WHEN TO USE

  • User account status
  • Order status (pending/shipped/delivered)
  • Traffic light
  • Media player (play/pause/stop)
❌ Problem — if/else everywhere
function doAction(user) {
  if      (user.status === "active")  { /* ... */ }
  else if (user.status === "banned")  { /* ... */ }
  else if (user.status === "pending") { /* ... */ }
}
✅ State — each state handles itself
class ActiveState {
  login()  { return "✅ Welcome back!";     }
  post()   { return "📝 Post published!";   }
}
class BannedState {
  login()  { return "❌ Account banned!";   }
  post()   { return "❌ Cannot post!";       }
}
class PendingState {
  login()  { return "⏳ Verify email first"; }
  post()   { return "⏳ Not activated yet";  }
}

class UserAccount {
  constructor() { this.state = new PendingState(); }
  setState(s)   { this.state = s; }
  login()       { return this.state.login(); }
  post()        { return this.state.post(); }
}

const acc = new UserAccount();
acc.login();                          // ⏳ Verify email
acc.setState(new ActiveState());
acc.login();                          // ✅ Welcome back! ✅
// INTERVIEW QUESTIONS
20 Template Method BEHAVIORAL

🎯 PROBLEM IT SOLVES

All user types log in with the same steps (validate → authenticate → log) but each type implements each step its own way.

💡 WHEN TO USE

  • Login flow for different user types
  • Export report (same steps, different formats)
  • Build pipelines
✅ Template Method — same flow, different steps
class LoginTemplate {
  login(data) { // the template — never changes
    this.validate(data);
    this.authenticate(data);
    this.logSuccess(data);
  }
  logSuccess(d){ console.log("✅ Logged: "+d.user); } // default
  validate()    { throw "implement validate"; }
  authenticate(){ throw "implement authenticate"; }
}

class EmailLogin extends LoginTemplate {
  validate(d)      { console.log("📧 Validate email: "+d.email); }
  authenticate(d)  { console.log("🔑 Check password"); }
}
class GoogleLogin extends LoginTemplate {
  validate(d)      { console.log("🔵 Validate token: "+d.token); }
  authenticate(d)  { console.log("🔵 Verify with Google"); }
}

new EmailLogin().login({ email:"ali@x.com", user:"Ali" }); // ✅
// INTERVIEW QUESTIONS
21 Chain of Responsibility BEHAVIORAL

🎯 PROBLEM IT SOLVES

When a user sends a request, it passes through checkpoints: Are they logged in? Do they have permission? Is the data valid? Each checkpoint decides to handle or pass along.

💡 WHEN TO USE

  • Auth → Permission → Validation
  • Express.js middleware
  • Support ticket escalation
✅ Chain — each check is independent
class Middleware {
  setNext(m) { this.next = m; return m; }
  handle(req) { return this.next?.handle(req); }
}

class AuthCheck extends Middleware {
  handle(req) {
    if (!req.user) return "❌ Login first!";
    return super.handle(req);
  }
}
class AdminCheck extends Middleware {
  handle(req) {
    if (!req.user.isAdmin) return "❌ Admins only!";
    return super.handle(req);
  }
}
class Handler extends Middleware {
  handle() { return "✅ Welcome Admin!"; }
}

const chain = new AuthCheck();
chain.setNext(new AdminCheck()).setNext(new Handler());
chain.handle({ user: { name:"Ali", isAdmin:true } }); // ✅
// INTERVIEW QUESTIONS
22 Visitor BEHAVIORAL

🎯 PROBLEM IT SOLVES

You have different user types (FreeUser, PremiumUser) and want to perform operations on them (export, report, discount) without modifying the user classes.

💡 WHEN TO USE

  • Reports across different user types
  • Export in different formats
  • Add operations without changing classes
✅ Visitor — operations from outside
class FreeUser    { accept(v){ v.visitFree(this); }; name="Ali"; }
class PremiumUser { accept(v){ v.visitPremium(this); }; name="Ahmed"; }

// New visitor without touching the classes
class DiscountVisitor {
  visitFree(u)    { console.log(`${u.name}: 10% discount 🎁`); }
  visitPremium(u) { console.log(`${u.name}: 30% discount 🎁`); }
}
class ReportVisitor {
  visitFree(u)    { console.log(`${u.name}: Free plan 📊`); }
  visitPremium(u) { console.log(`${u.name}: Premium plan 📊`); }
}

const users = [new FreeUser(), new PremiumUser()];
users.forEach(u => u.accept(new DiscountVisitor())); // ✅
// INTERVIEW QUESTIONS
23 Interpreter BEHAVIORAL

🎯 PROBLEM IT SOLVES

User types a search query like "name=Ali AND age>20" — you need to understand and translate that text into a real filter.

💡 WHEN TO USE

  • User search / filter queries
  • SQL parser
  • Template engine
  • Math expression calculator
✅ Interpreter — translate the expression
// Simple filter system for users
class NameFilter {
  constructor(name) { this.name = name; }
  interpret(users) {
    return users.filter(u => u.name === this.name);
  }
}
class AgeFilter {
  constructor(min) { this.min = min; }
  interpret(users) {
    return users.filter(u => u.age > this.min);
  }
}
class AndFilter {
  constructor(a, b) { this.a=a; this.b=b; }
  interpret(users) {
    return this.b.interpret(this.a.interpret(users));
  }
}

const users = [
  { name:"Ali",   age:25 },
  { name:"Ali",   age:17 },
  { name:"Ahmed", age:30 }
];
// "name=Ali AND age>20"
const query = new AndFilter(new NameFilter("Ali"), new AgeFilter(20));
query.interpret(users); // [{ name:"Ali", age:25 }] ✅
// INTERVIEW QUESTIONS

JavaScript Patterns

4 patterns
24 Constructor Pattern JS PATTERN

🎯 PROBLEM IT SOLVES

You want to create many users all with the same shape — same properties and same methods. Constructor gives you a blueprint to stamp out instances.

💡 WHEN TO USE

  • Create many users from the same template
  • OOP in JavaScript
  • Add methods on the prototype
❌ Problem — repetition everywhere
// Every user requires writing the same methods again 😩
const ali   = { name:"Ali",   greet() { return "Hi, I'm Ali";   } };
const ahmed = { name:"Ahmed", greet() { return "Hi, I'm Ahmed"; } };
✅ Constructor — one blueprint for all
// function constructor (old way)
function User(name, age) {
  this.name = name;
  this.age  = age;
}
// method on prototype (shared by all instances)
User.prototype.greet = function() {
  return `Hi, I'm ${this.name}!`;
};

// class syntax (modern way — same idea)
class User {
  constructor(name, age) { this.name=name; this.age=age; }
  greet() { return `Hi, I'm ${this.name}!`; }
}

const ali   = new User("Ali",   25);
const ahmed = new User("Ahmed", 30);
ali.greet();   // "Hi, I'm Ali!" ✅
ahmed.greet(); // "Hi, I'm Ahmed!" ✅
// INTERVIEW QUESTIONS
25 Module Pattern JS PATTERN

🎯 PROBLEM IT SOLVES

Sensitive user data (like passwords) shouldn't be visible or editable from outside. Module hides private data and only exposes what's needed.

💡 WHEN TO USE

  • Hide sensitive data
  • Encapsulation in JS
  • Organize code into units
❌ Problem — everything is public
let userName     = "Ali";
let userPassword = "1234"; // Anyone can read and modify it! 😩
userName = "Hacker"; // so easy to tamper with
✅ Module — private + public
const UserModule = (function() {
  // ❌ private — not accessible from outside
  let _password = "1234";
  let _name     = "Ali";

  // ✅ public — this is what we expose
  return {
    getName() { return _name; },
    setName(n) {
      if (n.length > 2) _name = n; // validation
    },
    checkPassword(p) { return p === _password; }
  };
})();

UserModule.getName();         // "Ali" ✅
UserModule._password;          // undefined ✅ (protected by closure!)
UserModule.checkPassword("1234"); // true ✅
// INTERVIEW QUESTIONS
26 Revealing Module JS PATTERN

🎯 PROBLEM IT SOLVES

An improvement on Module Pattern — instead of writing some functions inside the return and others outside, write everything inside and only "reveal" what you want.

💡 WHEN TO USE

  • When you want all code organized in one place
  • Easier to read and maintain
  • Clearly define what is public and what is private
❌ Regular Module — functions split across two places
const UserModule = (function() {
  let name = "Ali";
  function validate(n) { return n.length > 2; } // private here
  return {
    setName(n) { // public here — two different places 😕
      if (validate(n)) name = n;
    }
  };
})();
✅ Revealing Module — everything in one place
const UserProfile = (function() {
  let _name  = "Ali";
  let _email = "ali@x.com";

  function _validate(n) { return n.length > 2; }

  function getName()   { return _name; }
  function getEmail()  { return _email; }
  function setName(n)  { if (_validate(n)) _name = n; }

  // ✅ only here you define what gets revealed
  return { getName, getEmail, setName };
})();

UserProfile.getName();          // "Ali" ✅
UserProfile.setName("Ahmed");
UserProfile.getName();          // "Ahmed" ✅
UserProfile._validate;            // undefined ✅ (private)
// INTERVIEW QUESTIONS
27 Mixin Pattern JS PATTERN

🎯 PROBLEM IT SOLVES

User and Admin share behaviors (canLogin, canPost) but you don't want complex inheritance. Mixin adds behaviors to any class without using extends.

💡 WHEN TO USE

  • Add behaviors to different classes
  • When JS single inheritance limits you
  • Reusable behaviors without inheritance
❌ Problem — code duplication
class User  { canLogin() {/* same code */} canPost(){/* same code */} }
class Admin { canLogin() {/* same code */} canPost(){/* same code */} }
// Same code copy-pasted everywhere 😩
✅ Mixin — share behaviors
// Mixin — reusable behaviors
const UserMixin = {
  canLogin() { return `✅ ${this.name} logged in`; },
  canPost()  { return `📝 ${this.name} posted`;   },
  getProfile(){ return `👤 ${this.name} - ${this.role}`; }
};

class NormalUser { constructor(name){ this.name=name; this.role="user";  } }
class AdminUser  { constructor(name){ this.name=name; this.role="admin"; } }

// Add the Mixin to both classes
Object.assign(NormalUser.prototype, UserMixin);
Object.assign(AdminUser.prototype,  UserMixin);

const ali   = new NormalUser("Ali");
const admin = new AdminUser("Ahmed");
ali.canLogin();    // Ali logged in ✅
admin.getProfile(); // 👤 Ahmed - admin ✅
// INTERVIEW QUESTIONS
Answered: 0
Correct: 0
Patterns: 0 /27
0%