codejump

Interview questionsDesign Patterns

Design Patterns interview questions and answers

21 Design Patterns questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.

Junior level Design Patterns questions

  1. 1.What does the Observer pattern do?

    javascript
    class EventEmitter {
      constructor() {
        this.events = {};
      }
      
      on(event, callback) {
        if (!this.events[event]) {
          this.events[event] = [];
        }
        this.events[event].push(callback);
      }
      
      emit(event, data) {
        if (this.events[event]) {
          this.events[event].forEach(callback => callback(data));
        }
      }
    }
    
    // Usage
    const emitter = new EventEmitter();
    
    emitter.on("userLogin", (user) => {
      console.log(`User logged in: ${user}`);
    });
    
    emitter.on("userLogin", (user) => {
      console.log(`Send welcome email to ${user}`);
    });
    
    emitter.emit("userLogin", "Alice");
    // Output:
    // User logged in: Alice
    // Send welcome email to Alice
    • A.Establishes a one-to-many relationship where many objects listen to state changes of one object.
    • B.Observes user mouse movements.
    • C.Creates a backup (observer) of data.
    • D.Prevents objects from changing state.
    Show answer

    Answer: A. Establishes a one-to-many relationship where many objects listen to state changes of one object.

    The Observer pattern allows multiple objects (observers) to subscribe to events from a subject and get notified when the subject's state changes. Example: Real-world examples:
    • Event listeners in the DOM
    • Publish-Subscribe systems
    • MVC frameworks

    From the quiz Creational Patterns

  2. 2.What is the Module pattern used for?

    javascript
    const Counter = (() => {
      let count = 0; // Private variable
      
      return {
        // Public methods
        increment() {
          count++;
          return count;
        },
        
        decrement() {
          count--;
          return count;
        },
        
        getCount() {
          return count;
        }
      };
    })();
    
    console.log(Counter.increment()); // 1
    console.log(Counter.increment()); // 2
    console.log(Counter.count); // undefined (private)
    • A.Creating a module installation system.
    • B.Importing external modules only.
    • C.Encapsulating private and public methods/variables.
    • D.Creating modular HTML structures.
    Show answer

    Answer: C. Encapsulating private and public methods/variables.

    The Module pattern uses closures to create private and public APIs, encapsulating internal logic. Example: Benefits:
    • Encapsulation (private data)
    • Namespace management
    • Revealing public API
    • Preventing global pollution Real-world example:

    From the quiz Creational Patterns

  3. 3.What does the Decorator pattern do?

    javascript
    class Coffee {
      cost() {
        return 5;
      }
      description() {
        return "Plain coffee";
      }
    }
    
    // Decorator: Add milk
    function addMilk(coffee) {
      const originalCost = coffee.cost;
      const originalDescription = coffee.description;
      
      coffee.cost = function() {
        return originalCost.call(this) + 2;
      };
      
      coffee.description = function() {
        return originalDescription.call(this) + ", with milk";
      };
      
      return coffee;
    }
    
    // Decorator: Add sugar
    function addSugar(coffee) {
      const originalCost = coffee.cost;
      const originalDescription = coffee.description;
      
      coffee.cost = function() {
        return originalCost.call(this) + 1;
      };
      
      coffee.description = function() {
        return originalDescription.call(this) + ", with sugar";
      };
      
      return coffee;
    }
    
    // Usage
    let coffee = new Coffee();
    coffee = addMilk(coffee);
    coffee = addSugar(coffee);
    
    console.log(coffee.cost()); // 8 (5 + 2 + 1)
    console.log(coffee.description()); // "Plain coffee, with milk, with sugar"
    • A.Decorates HTML elements visually.
    • B.Creates decorative patterns in code.
    • C.Adds functionality to objects dynamically without modifying the original object.
    • D.Prevents objects from being modified.
    Show answer

    Answer: C. Adds functionality to objects dynamically without modifying the original object.

    The Decorator pattern allows adding new functionality to objects dynamically by wrapping them, without changing the original object. Example:

    From the quiz Creational Patterns

  4. 4.What does the Strategy pattern allow?

    javascript
    // Different payment strategies
    class PaymentStrategy {
    }
    
    class CreditCardPayment extends PaymentStrategy {
      pay(amount) {
        return `Paid $${amount} via credit card`;
      }
    }
    
    class PayPalPayment extends PaymentStrategy {
      pay(amount) {
        return `Paid $${amount} via PayPal`;
      }
    }
    
    class CryptoPayment extends PaymentStrategy {
      pay(amount) {
        return `Paid $${amount} via Crypto`;
      }
    }
    
    // Context that uses strategies
    class ShoppingCart {
      constructor(paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
      }
      
      checkout(amount) {
        return this.paymentStrategy.pay(amount);
      }
    }
    
    // Usage (choose strategy at runtime)
    const creditCardPayment = new CreditCardPayment();
    const cart1 = new ShoppingCart(creditCardPayment);
    console.log(cart1.checkout(100)); // "Paid $100 via credit card"
    
    const paypalPayment = new PayPalPayment();
    const cart2 = new ShoppingCart(paypalPayment);
    console.log(cart2.checkout(50)); // "Paid $50 via PayPal"
    • A.Creating a strategy for winning games.
    • B.Preventing users from changing settings.
    • C.Storing strategies in a database.
    • D.Selecting an algorithm's behavior at runtime without changing client code.
    Show answer

    Answer: D. Selecting an algorithm's behavior at runtime without changing client code.

    The Strategy pattern defines a set of interchangeable algorithms and lets you select which one to use at runtime. Example: Use cases:
    • Different payment methods
    • Different sorting algorithms
    • Different validation rules
    • Different compression algorithms

    From the quiz Creational Patterns

  5. 5.What does the Adapter pattern do?

    javascript
    // Old API that returns data in one format
    class OldWeatherAPI {
      getWeather() {
        return {
          temp_celsius: 25,
          weather_condition: "sunny"
        };
      }
    }
    
    // New API expects different format
    class WeatherApp {
      setWeather(data) {
        console.log(`Temperature: ${data.temperature}°F`);
        console.log(`Condition: ${data.condition}`);
      }
    }
    
    // Adapter bridges the gap
    class WeatherAdapter {
      constructor(oldAPI) {
        this.oldAPI = oldAPI;
      }
      
      getFormattedWeather() {
        const oldData = this.oldAPI.getWeather();
        return {
          temperature: (oldData.temp_celsius * 9/5) + 32, // Convert to Fahrenheit
          condition: oldData.weather_condition
        };
      }
    }
    
    // Usage
    const oldAPI = new OldWeatherAPI();
    const adapter = new WeatherAdapter(oldAPI);
    const app = new WeatherApp();
    app.setWeather(adapter.getFormattedWeather());
    // Temperature: 77°F
    // Condition: sunny
    • A.Adapts to different operating systems.
    • B.Makes incompatible interfaces compatible by wrapping one interface with another.
    • C.Adapts code to different browsers.
    • D.Prevents interface changes.
    Show answer

    Answer: B. Makes incompatible interfaces compatible by wrapping one interface with another.

    The Adapter pattern converts the interface of one class into another that clients expect, allowing incompatible classes to work together. Example:

    From the quiz Creational Patterns

  6. 6.What does the Proxy pattern do?

    javascript
    // Real object
    class RealDatabase {
      getData(id) {
        return `Data for user ${id}`;
      }
    }
    
    // Proxy that controls access
    class DatabaseProxy {
      constructor(realDB) {
        this.realDB = realDB;
      }
      
      getData(id) {
        // Add extra logic (logging, caching, access control, etc.)
        console.log(`Accessing database for user ${id}`);
        
        // Check permissions
        if (!this.hasPermission(id)) {
          throw new Error("Access denied");
        }
        
        // Call the real object
        return this.realDB.getData(id);
      }
      
      hasPermission(id) {
        return true; // Check actual permissions
      }
    }
    
    // Usage
    const realDB = new RealDatabase();
    const proxy = new DatabaseProxy(realDB);
    console.log(proxy.getData(1)); // Calls through proxy, adding extra logic
    • A.Creates a proxy server for networking.
    • B.Creates a copy of an object.
    • C.Proxies network requests to a database.
    • D.Provides a surrogate or placeholder for another object to control access to it.
    Show answer

    Answer: D. Provides a surrogate or placeholder for another object to control access to it.

    The Proxy pattern creates a placeholder object that controls access to another object, allowing you to add extra logic before/after accessing it. Example: Use cases:
    • Lazy initialization (create expensive objects only when needed)
    • Access control (check permissions)
    • Caching
    • Logging
    • Lazy loading

    From the quiz Creational Patterns

  7. 7.What does the Iterator pattern do?

    javascript
    class MyCollection {
      constructor(items) {
        this.items = items;
      }
      
      getIterator() {
        return new MyIterator(this.items);
      }
    }
    
    class MyIterator {
      constructor(items) {
        this.items = items;
        this.index = 0;
      }
      
      hasNext() {
        return this.index < this.items.length;
      }
      
      next() {
        return this.items[this.index++];
      }
    }
    
    // Usage
    const collection = new MyCollection(["A", "B", "C"]);
    const iterator = collection.getIterator();
    
    while (iterator.hasNext()) {
      console.log(iterator.next());
    }
    // Output: A, B, C
    • A.Iterates files on a computer.
    • B.Provides a way to access elements sequentially without exposing the collection's structure.
    • C.Creates loops in code.
    • D.Prevents iteration over collections.
    Show answer

    Answer: B. Provides a way to access elements sequentially without exposing the collection's structure.

    The Iterator pattern provides a standard way to traverse a collection without exposing how it's structured internally. Example: Modern JavaScript iterators:

    From the quiz Creational Patterns

Mid level Design Patterns questions

  1. 8.What does the State pattern do?

    javascript
    // Different states
    class State {
      play() { }
      pause() { }
      stop() { }
    }
    
    class PlayingState extends State {
      constructor(player) {
        super();
        this.player = player;
      }
      
      play() {
        console.log("Already playing");
      }
      
      pause() {
        console.log("Pausing...");
        this.player.setState(new PausedState(this.player));
      }
      
      stop() {
        console.log("Stopping...");
        this.player.setState(new StoppedState(this.player));
      }
    }
    
    class PausedState extends State {
      constructor(player) {
        super();
        this.player = player;
      }
      
      play() {
        console.log("Resuming...");
        this.player.setState(new PlayingState(this.player));
      }
      
      pause() {
        console.log("Already paused");
      }
      
      stop() {
        console.log("Stopping...");
        this.player.setState(new StoppedState(this.player));
      }
    }
    
    class StoppedState extends State {
      constructor(player) {
        super();
        this.player = player;
      }
      
      play() {
        console.log("Playing...");
        this.player.setState(new PlayingState(this.player));
      }
      
      pause() {
        console.log("Cannot pause when stopped");
      }
      
      stop() {
        console.log("Already stopped");
      }
    }
    
    // Context
    class MediaPlayer {
      constructor() {
        this.state = new StoppedState(this);
      }
      
      setState(state) {
        this.state = state;
      }
      
      play() {
        this.state.play();
      }
      
      pause() {
        this.state.pause();
      }
      
      stop() {
        this.state.stop();
      }
    }
    
    // Usage
    const player = new MediaPlayer();
    player.play(); // "Playing..."
    player.pause(); // "Pausing..."
    player.play(); // "Resuming..."
    • A.Allows an object to alter its behavior when its internal state changes.
    • B.Maintains the state of an application.
    • C.Stores state in a database.
    • D.Prevents state changes.
    Show answer

    Answer: A. Allows an object to alter its behavior when its internal state changes.

    The State pattern allows an object to change its behavior based on its internal state, making the state transitions explicit and encapsulated. Example:

    From the quiz Structural Patterns

  2. 9.What does the Facade pattern do?

    javascript
    // Complex subsystems
    class CPU {
      freeze() {
        console.log("Freezing CPU");
      }
      
      jump(position) {
        console.log(`CPU jumping to ${position}`);
      }
      
      execute() {
        console.log("CPU executing");
      }
    }
    
    class Memory {
      load(position, data) {
        console.log(`Loading ${data} into memory at ${position}`);
      }
    }
    
    class Disk {
      read(sector, size) {
        console.log(`Reading ${size} bytes from sector ${sector}`);
      }
    }
    
    // Facade
    class Computer {
      constructor() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.disk = new Disk();
      }
      
      startComputer() {
        console.log("Starting computer...");
        this.cpu.freeze();
        this.memory.load(0, "OS");
        this.disk.read(0, 1024);
        this.cpu.jump(0);
        this.cpu.execute();
        console.log("Computer started!");
      }
    }
    
    // Usage (simple interface for complex operations)
    const computer = new Computer();
    computer.startComputer();
    // Instead of manually calling all subsystems
    • A.Provides the front-facing part of a building.
    • B.Creates a facade (fake) object.
    • C.Hides code from users.
    • D.Simplifies a complex subsystem by providing a unified interface.
    Show answer

    Answer: D. Simplifies a complex subsystem by providing a unified interface.

    The Facade pattern provides a simplified, unified interface to a complex set of subsystems, making them easier to use. Example: Real-world examples:
    • jQuery ($) facade over DOM API
    • React Router facade over history API
    • Fetch API facade over XMLHttpRequest

    From the quiz Structural Patterns

  3. 10.What does the Chain of Responsibility pattern do?

    javascript
    // Handler interface
    class Handler {
      setNext(handler) {
        this.nextHandler = handler;
        return handler;
      }
      
      handle(request) { }
    }
    
    // Concrete handlers
    class AuthHandler extends Handler {
      handle(request) {
        if (!request.user) {
          console.log("AuthHandler: User not authenticated");
          return false;
        }
        console.log("AuthHandler: User authenticated");
        
        if (this.nextHandler) {
          return this.nextHandler.handle(request);
        }
        return true;
      }
    }
    
    class ValidationHandler extends Handler {
      handle(request) {
        if (!request.data) {
          console.log("ValidationHandler: Invalid data");
          return false;
        }
        console.log("ValidationHandler: Data valid");
        
        if (this.nextHandler) {
          return this.nextHandler.handle(request);
        }
        return true;
      }
    }
    
    class LoggingHandler extends Handler {
      handle(request) {
        console.log(`LoggingHandler: Logging request for ${request.user}`);
        
        if (this.nextHandler) {
          return this.nextHandler.handle(request);
        }
        return true;
      }
    }
    
    // Build the chain
    const auth = new AuthHandler();
    const validation = new ValidationHandler();
    const logging = new LoggingHandler();
    
    auth.setNext(validation).setNext(logging);
    
    // Process request through chain
    const request = { user: "Alice", data: { id: 1 } };
    auth.handle(request);
    // AuthHandler: User authenticated
    // ValidationHandler: Data valid
    // LoggingHandler: Logging request for Alice
    • A.Passes a request along a chain of handlers until one handles it.
    • B.Creates a chain of objects in a list.
    • C.Creates responsibility for each object in a chain.
    • D.Prevents requests from being handled.
    Show answer

    Answer: A. Passes a request along a chain of handlers until one handles it.

    The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides to process it or pass it along. Example: Use cases:
    • Event handling (bubbling)
    • Middleware in Express
    • Approval workflows
    • Logging levels

    From the quiz Structural Patterns

  4. 11.What does the Template Method pattern do?

    javascript
    // Base class with template method
    class DataProcessor {
      // Template method (final algorithm structure)
      process(data) {
        const extracted = this.extract(data);
        const transformed = this.transform(extracted);
        const validated = this.validate(transformed);
        this.store(validated);
      }
      
      extract(data) { } // Subclasses override
      transform(data) { } // Subclasses override
      validate(data) { } // Subclasses override
      store(data) { } // Subclasses override
    }
    
    // Concrete implementation
    class JSONDataProcessor extends DataProcessor {
      extract(data) {
        console.log("Extracting JSON data");
        return JSON.parse(data);
      }
      
      transform(data) {
        console.log("Transforming JSON");
        return { ...data, timestamp: Date.now() };
      }
      
      validate(data) {
        console.log("Validating JSON");
        return data.id ? data : null;
      }
      
      store(data) {
        console.log("Storing JSON to database");
      }
    }
    
    // Different implementation
    class CSVDataProcessor extends DataProcessor {
      extract(data) {
        console.log("Extracting CSV data");
        return data.split(",");
      }
      
      transform(data) {
        console.log("Transforming CSV");
        return { values: data, timestamp: Date.now() };
      }
      
      validate(data) {
        console.log("Validating CSV");
        return data.values.length > 0 ? data : null;
      }
      
      store(data) {
        console.log("Storing CSV to database");
      }
    }
    
    // Usage
    const jsonProcessor = new JSONDataProcessor();
    jsonProcessor.process('{"id": 1, "name": "Alice"}');
    
    const csvProcessor = new CSVDataProcessor();
    csvProcessor.process("1,2,3,4,5");
    • A.Creates a template for HTML.
    • B.Prevents algorithm customization.
    • C.Generates template strings.
    • D.Defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.
    Show answer

    Answer: D. Defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.

    The Template Method pattern defines a fixed structure of an algorithm in a base class, allowing subclasses to override specific steps. Example: Benefits:
    • Avoids code duplication
    • Enforces algorithm structure
    • Allows customization of specific steps

    From the quiz Structural Patterns

  5. 12.What does the Composite pattern do?

    javascript
    // Component interface
    class FileSystemComponent {
      getSize() { }
      display() { }
    }
    
    // Leaf: Individual file
    class File extends FileSystemComponent {
      constructor(name, size) {
        super();
        this.name = name;
        this.size = size;
      }
      
      getSize() {
        return this.size;
      }
      
      display(indent = 0) {
        console.log(" ".repeat(indent) + this.name + ` (${this.size} KB)`);
      }
    }
    
    // Composite: Directory containing files and subdirectories
    class Directory extends FileSystemComponent {
      constructor(name) {
        super();
        this.name = name;
        this.children = [];
      }
      
      add(component) {
        this.children.push(component);
      }
      
      getSize() {
        return this.children.reduce((total, child) => total + child.getSize(), 0);
      }
      
      display(indent = 0) {
        console.log(" ".repeat(indent) + this.name + "/");
        this.children.forEach(child => child.display(indent + 2));
      }
    }
    
    // Usage
    const root = new Directory("root");
    
    const documents = new Directory("Documents");
    const file1 = new File("resume.pdf", 50);
    const file2 = new File("letter.doc", 30);
    documents.add(file1);
    documents.add(file2);
    
    const photos = new Directory("Photos");
    const photo1 = new File("vacation.jpg", 200);
    photos.add(photo1);
    
    root.add(documents);
    root.add(photos);
    
    root.display();
    // root/
    //   Documents/
    //     resume.pdf (50 KB)
    //     letter.doc (30 KB)
    //   Photos/
    //     vacation.jpg (200 KB)
    
    console.log(`Total size: ${root.getSize()} KB`); // 280 KB
    • A.Composes multiple objects into one.
    • B.Allows treating individual objects and compositions of objects uniformly.
    • C.Creates composite data types.
    • D.Prevents composition of objects.
    Show answer

    Answer: B. Allows treating individual objects and compositions of objects uniformly.

    The Composite pattern allows individual objects and compositions to be treated with the same interface, forming tree-like structures. Example: Real-world examples:
    • File systems
    • DOM tree
    • Organization hierarchies
    • UI component trees

    From the quiz Structural Patterns

  6. 13.What does the Prototype pattern do?

    javascript
    // Prototype (original object)
    class User {
      constructor(name, email) {
        this.name = name;
        this.email = email;
      }
      
      clone() {
        return new User(this.name, this.email);
      }
    }
    
    // Usage
    const user1 = new User("Alice", "alice@example.com");
    const user2 = user1.clone();
    
    console.log(user2.name); // "Alice"
    console.log(user1 === user2); // false (different objects)
    • A.Creates a prototype version of an application.
    • B.Creates a prototype website.
    • C.Prevents object cloning.
    • D.Creates new objects by cloning an existing object (prototype).
    Show answer

    Answer: D. Creates new objects by cloning an existing object (prototype).

    The Prototype pattern creates new objects by copying an existing object (prototype) instead of creating from scratch. Example: Deep vs Shallow clone: Use cases:
    • Object cloning
    • Default configurations
    • Template objects

    From the quiz Structural Patterns

  7. 14.Which pattern is best for a document editor that needs Undo/Redo functionality?

    javascript
    class TextEditor {
      constructor() {
        this.text = "";
        this.history = [];
        this.future = [];
      }
      
      executeCommand(command) {
        command.execute(this);
        this.history.push(command);
        this.future = []; // Clear future on new command
      }
      
      undo() {
        const command = this.history.pop();
        if (command) {
          command.undo(this);
          this.future.push(command);
        }
      }
      
      redo() {
        const command = this.future.pop();
        if (command) {
          command.execute(this);
          this.history.push(command);
        }
      }
    }
    
    class AddTextCommand {
      constructor(text) {
        this.text = text;
      }
      
      execute(editor) {
        editor.text += this.text;
      }
      
      undo(editor) {
        editor.text = editor.text.slice(0, -this.text.length);
      }
    }
    
    const editor = new TextEditor();
    editor.executeCommand(new AddTextCommand("Hello "));
    editor.executeCommand(new AddTextCommand("World"));
    console.log(editor.text); // "Hello World"
    
    editor.undo();
    console.log(editor.text); // "Hello "
    
    editor.redo();
    console.log(editor.text); // "Hello World"
    • A.Observer pattern
    • B.Command pattern
    • C.Adapter pattern
    • D.Strategy pattern
    Show answer

    Answer: B. Command pattern

    The Command pattern is ideal for Undo/Redo because: 1. Each action is encapsulated as a command object 2. Commands can be stored in a history 3. Commands can be undone and redone Example:

    From the quiz Structural Patterns

Senior level Design Patterns questions

  1. 15.What does the Flyweight pattern do?

    javascript
    // Each tree object stores all data
    class Tree {
      constructor(x, y, type, color, texture) {
        this.x = x;
        this.y = y;
        this.type = type; // Repeated for all trees of same type
        this.color = color; // Repeated
        this.texture = texture; // Repeated
      }
    }
    
    // Forest with 1 million trees = tons of memory waste
    const forest = [];
    for (let i = 0; i < 1000000; i++) {
      forest.push(new Tree(Math.random() * 1000, Math.random() * 1000, "oak", "green", "rough"));
    }
    • A.Makes objects lightweight (small file size).
    • B.Compresses objects in memory.
    • C.Prevents object creation to save memory.
    • D.Shares common data between many objects to reduce memory usage.
    Show answer

    Answer: D. Shares common data between many objects to reduce memory usage.

    The Flyweight pattern reduces memory usage by sharing common immutable data between many objects. Example (without Flyweight - high memory usage): Example (with Flyweight - low memory usage): Real-world examples:
    • String interning (reusing identical strings)
    • Font characters (each character is a flyweight)
    • Game sprites
    • Connection pools

    From the quiz Behavioral Patterns

  2. 16.What does the Bridge pattern do?

    javascript
    // Abstraction and implementation tightly coupled
    class Circle {
      draw() { }
    }
    
    class RedCircle extends Circle {
      draw() {
        // Red + Circle logic combined
        this.drawRedColor();
        this.drawCircleShape();
      }
    }
    
    class BlueCircle extends Circle {
      draw() {
        this.drawBlueColor();
        this.drawCircleShape();
      }
    }
    
    // Adding new shapes: RedSquare, BlueSquare, etc. = exponential growth
    • A.Connects two systems together.
    • B.Prevents implementation changes.
    • C.Creates a bridge between objects.
    • D.Decouples an abstraction from its implementation so they can vary independently.
    Show answer

    Answer: D. Decouples an abstraction from its implementation so they can vary independently.

    The Bridge pattern separates abstraction from implementation, allowing them to change independently. Without Bridge (rigid): With Bridge (flexible): Benefits:
    • Add shapes and colors independently (2+2 combinations, not 2*2)
    • Reduce class hierarchy explosion
    • Change implementation without affecting abstraction

    From the quiz Behavioral Patterns

  3. 17.What will be logged in this chain of responsibility setup?

    javascript
    class Handler {
      setNext(handler) {
        this.nextHandler = handler;
        return handler;
      }
      
      handle(request) { }
    }
    
    class InfoHandler extends Handler {
      handle(request) {
        if (request.level === "info") {
          console.log(`[INFO] ${request.message}`);
          return;
        }
        this.nextHandler?.handle(request);
      }
    }
    
    class ErrorHandler extends Handler {
      handle(request) {
        if (request.level === "error") {
          console.log(`[ERROR] ${request.message}`);
          return;
        }
        this.nextHandler?.handle(request);
      }
    }
    
    const infoHandler = new InfoHandler();
    const errorHandler = new ErrorHandler();
    infoHandler.setNext(errorHandler);
    
    infoHandler.handle({ level: "info", message: "App started" });
    infoHandler.handle({ level: "error", message: "Connection failed" });
    infoHandler.handle({ level: "debug", message: "Debug info" });
    • A.[INFO] App started, [ERROR] Connection failed, and nothing for debug
    • B.[INFO] App started and [ERROR] Connection failed
    • C.[INFO] App started, [ERROR] Connection failed, and error for debug
    • D.All three requests are logged
    Show answer

    Answer: A. [INFO] App started, [ERROR] Connection failed, and nothing for debug

    Step by step: 1. infoHandler.handle({ level: "info", message: "App started" })
    • Level is info → logs [INFO] App started → returns 2. infoHandler.handle({ level: "error", message: "Connection failed" })
    • Level is not info → passes to errorHandler
    • errorHandler checks level error → logs [ERROR] Connection failed → returns 3. infoHandler.handle({ level: "debug", message: "Debug info" })
    • Level is not info → passes to errorHandler
    • errorHandler checks level not error → passes to nextHandler (undefined)
    • Nothing is logged (chain ends) Output:

    From the quiz Behavioral Patterns

  4. 18.What potential issue exists in this Observer implementation?

    javascript
    class Subject {
      constructor() {
        this.observers = [];
      }
      
      subscribe(observer) {
        this.observers.push(observer);
      }
      
      notify(data) {
        this.observers.forEach(obs => obs.update(data));
      }
    }
    
    class Observer {
      update(data) {
        console.log("Updated with:", data);
      }
    }
    
    const subject = new Subject();
    let observer = new Observer();
    
    subject.subscribe(observer);
    subject.notify({ message: "Hello" });
    
    // Later, the local reference is dropped but...
    observer = null; // the entry in subject.observers still points at it!
    subject.notify({ message: "World" }); // Observer still called (memory leak!)
    • A.No issue; observers are cleaned up automatically.
    • B.TypeError when observer is set to null.
    • C.Memory leak because observers are never removed from the array.
    • D.Subject will crash when notifying.
    Show answer

    Answer: C. Memory leak because observers are never removed from the array.

    The observer is added to the observers array but never removed. Even after the local observer variable is set to null, the reference still held in subject.observers keeps the object alive, so it keeps receiving notifications — a memory leak. Fix: Provide unsubscribe method: Better: Use WeakSet (if possible):

    From the quiz Behavioral Patterns

  5. 19.What will be the state after these operations?

    javascript
    class TextBox {
      constructor() {
        this.text = "";
        this.undoStack = [];
        this.redoStack = [];
      }
      
      executeCommand(command) {
        command.execute(this);
        this.undoStack.push(command);
        this.redoStack = []; // Clear redo when new command executed
      }
      
      undo() {
        if (this.undoStack.length > 0) {
          const command = this.undoStack.pop();
          command.undo(this);
          this.redoStack.push(command);
        }
      }
    }
    
    class AddCommand {
      constructor(text) {
        this.text = text;
      }
      
      execute(textBox) {
        textBox.text += this.text;
      }
      
      undo(textBox) {
        textBox.text = textBox.text.slice(0, -this.text.length);
      }
    }
    
    const textBox = new TextBox();
    textBox.executeCommand(new AddCommand("Hello"));
    textBox.executeCommand(new AddCommand(" "));
    textBox.executeCommand(new AddCommand("World"));
    textBox.undo();
    textBox.undo();
    textBox.executeCommand(new AddCommand("JavaScript"));
    • A."Hello WorldJavaScript"
    • B."HelloJavaScript"
    • C."Hello JavaScript"
    • D."HelloWorld"
    Show answer

    Answer: B. "HelloJavaScript"

    Step by step: 1. executeCommand(new AddCommand("Hello")) → text = Hello 2. executeCommand(new AddCommand(" ")) → text = Hello 3. executeCommand(new AddCommand("World")) → text = Hello World 4. undo() → text = Hello (remove World) 5. undo() → text = Hello (remove ) 6. executeCommand(new AddCommand("JavaScript")) → text = HelloJavaScript

    From the quiz Behavioral Patterns

  6. 20.Which strategy will be used in this code?

    javascript
    const strategies = {
      fast: {
        calculate(n) {
          return n * 2; // Fast but inaccurate
        }
      },
      accurate: {
        calculate(n) {
          let result = 0;
          for (let i = 0; i < n; i++) {
            result += i;
          }
          return result;
        }
      }
    };
    
    class Calculator {
      constructor(strategyName) {
        this.strategy = strategies[strategyName];
      }
      
      execute(n) {
        return this.strategy.calculate(n);
      }
    }
    
    const calc1 = new Calculator("fast");
    const calc2 = new Calculator("accurate");
    
    console.log(calc1.execute(5)); // 10
    console.log(calc2.execute(5)); // 10
    • A.They use different strategies
    • B.Both use accurate strategy
    • C.Both use fast strategy
    • D.Error: strategy is undefined
    Show answer

    Answer: A. They use different strategies

    • calc1 is initialized with "fast" strategy → strategies["fast"]
    • calc2 is initialized with "accurate" strategy → strategies["accurate"]
    • Different strategies are used, even though both happen to return 10 for input 5

    From the quiz Behavioral Patterns

  7. 21.For a class that needs to generate different types of reports (PDF, Excel, CSV) based on user selection, which pattern is most appropriate?

    javascript
    class ReportFactory {
      static createReport(type) {
        switch(type) {
          case "pdf":
            return new PDFReport();
          case "excel":
            return new ExcelReport();
          case "csv":
            return new CSVReport();
        }
      }
    }
    
    class PDFReport {
      generate(data) {
        return `PDF: ${JSON.stringify(data)}`;
      }
    }
    
    class ExcelReport {
      generate(data) {
        return `EXCEL: ${JSON.stringify(data)}`;
      }
    }
    
    class CSVReport {
      generate(data) {
        return `CSV: ${JSON.stringify(data)}`;
      }
    }
    
    // Usage
    const reportType = getUserSelection(); // "pdf", "excel", or "csv"
    const report = ReportFactory.createReport(reportType);
    const output = report.generate({ name: "Alice", age: 30 });
    • A.Singleton (only one report instance)
    • B.Strategy (vary the algorithm/format)
    • C.Factory (create reports without knowing exact class)
    • D.Adapter (adapt different formats)
    Show answer

    Answer: C. Factory (create reports without knowing exact class)

    Factory pattern is best for this use case because:
    • User selects report type
    • Factory creates the appropriate report class
    • Client doesn't need to know which exact class to instantiate Implementation:

    From the quiz Behavioral Patterns

Practise 50+ more Design Patterns questions

Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.