Back to blog
Jan 16, 2025
8 min read

Method Chaining

Implement a class with methods that can be chained together to perform operations.

Difficulty: Easy | Acceptance: 76.00% | Paid: No Topics: N/A

Implement a class that supports method chaining. The class should have methods that modify internal state and return the object itself, allowing multiple methods to be called in a single statement.

Create a class with the following methods:

  • add(value) - adds the given value to the current result
  • subtract(value) - subtracts the given value from the current result
  • multiply(value) - multiplies the current result by the given value
  • divide(value) - divides the current result by the given value
  • getResult() - returns the current result

Each method (except getResult) should return the object itself to enable chaining.

Table of Contents

Examples

Example 1

Input:

DataFrame animals:
+----------+---------+-----+--------+
| name     | species | age | weight |
+----------+---------+-----+--------+
| Tatiana  | Snake   | 98  | 464    |
| Khaled   | Giraffe | 50  | 41     |
| Alex     | Leopard | 6   | 328    |
| Jonathan | Monkey  | 45  | 463    |
| Stefan   | Bear    | 100 | 50     |
| Tommy    | Panda   | 26  | 349    |
+----------+---------+-----+--------+

Output:

+----------+
| name     |
+----------+
| Tatiana  |
| Jonathan |
| Tommy    |
| Alex     |
+----------+

Explanation: All animals weighing more than 100 should be included in the results table. Tatiana’s weight is 464, Jonathan’s weight is 463, Tommy’s weight is 349, and Alex’s weight is 328. The results should be sorted in descending order of weight.

Constraints

- 0 <= value <= 100
- The result will always fit in a 32-bit signed integer
- At most 100 operations will be performed

Approach 1: Standard Method Chaining

Intuition Store the current result in an instance variable and return this from each method to enable chaining.

Steps

  • Initialize the result to 0 in the constructor
  • For each operation method, modify the result and return this
  • The getResult method simply returns the current result
python
class Calculator:
    def __init__(self):
        self.result = 0
    
    def add(self, value: int) -> 'Calculator':
        self.result += value
        return self
    
    def subtract(self, value: int) -> 'Calculator':
        self.result -= value
        return self
    
    def multiply(self, value: int) -> 'Calculator':
        self.result *= value
        return self
    
    def divide(self, value: int) -> 'Calculator':
        self.result //= value
        return self
    
    def getResult(self) -> int:
        return self.result

Complexity

  • Time: O(1) for each operation
  • Space: O(1)
  • Notes: Simple and efficient, standard approach for method chaining

Approach 2: Builder Pattern

Intuition Use a separate builder class to construct the calculation step by step, then execute to get the result.

Steps

  • Create a Calculator class with a nested Builder
  • The Builder stores operations in a list
  • Execute runs all operations and returns the final result
python
from typing import List, Callable

class Calculator:
    def __init__(self):
        self.result = 0
        self.operations: List[Callable[[int], int]] = []
    
    def add(self, value: int) -> 'Calculator':
        self.operations.append(lambda x: x + value)
        self._apply_operations()
        return self
    
    def subtract(self, value: int) -> 'Calculator':
        self.operations.append(lambda x: x - value)
        self._apply_operations()
        return self
    
    def multiply(self, value: int) -> 'Calculator':
        self.operations.append(lambda x: x * value)
        self._apply_operations()
        return self
    
    def divide(self, value: int) -> 'Calculator':
        self.operations.append(lambda x: x // value)
        self._apply_operations()
        return self
    
    def _apply_operations(self):
        for op in self.operations:
            self.result = op(self.result)
        self.operations.clear()
    
    def getResult(self) -> int:
        return self.result

Complexity

  • Time: O(1) for each operation
  • Space: O(1) - operations list is cleared after each call
  • Notes: More complex than standard approach, useful for deferred execution

Approach 3: Functional Approach

Intuition Create immutable objects where each operation returns a new Calculator instance with the updated result.

Steps

  • Store result as an immutable property
  • Each operation creates a new Calculator with the updated result
  • This approach is more functional but less memory efficient
python
from dataclasses import dataclass

@dataclass
class Calculator:
    result: int = 0
    
    def add(self, value: int) -> 'Calculator':
        return Calculator(self.result + value)
    
    def subtract(self, value: int) -> 'Calculator':
        return Calculator(self.result - value)
    
    def multiply(self, value: int) -> 'Calculator':
        return Calculator(self.result * value)
    
    def divide(self, value: int) -> 'Calculator':
        return Calculator(self.result // value)
    
    def getResult(self) -> int:
        return self.result

Complexity

  • Time: O(1) for each operation
  • Space: O(n) where n is the number of chained operations
  • Notes: More memory intensive due to creating new objects, but provides immutability