Back to blog
Jun 24, 2024
5 min read

Calculator with Method Chaining

Design a Calculator class that supports method chaining for arithmetic operations like add, subtract, multiply, divide, and power.

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

Design a Calculator class. The class should provide the following methods:

  • add(value): Adds the given value to the current result and returns the calculator instance for chaining.
  • subtract(value): Subtracts the given value from the current result and returns the calculator instance for chaining.
  • multiply(value): Multiplies the current result by the given value and returns the calculator instance for chaining.
  • divide(value): Divides the current result by the given value and returns the calculator instance for chaining. If the value is 0, throw an error “Division by zero”.
  • power(value): Raises the current result to the power of the given value and returns the calculator instance for chaining.
  • getResult(): Returns the current result.

All methods except getResult() should support method chaining, meaning they return the calculator instance itself.

Examples

Example 1

Input: 
actions = ["Calculator", "add", "subtract", "getResult"], 
values = [[10], [5], [7], []]
Output: 8
Explanation: 
new Calculator(10) // 10
  .add(5)          // 10 + 5 = 15
  .subtract(7)     // 15 - 7 = 8
  .getResult()     // 8

Example 2

Input: 
actions = ["Calculator", "multiply", "power", "getResult"], 
values = [[2], [5], [2], []]
Output: 100
Explanation: 
new Calculator(2)   // 2
  .multiply(5)     // 2 * 5 = 10
  .power(2)        // 10² = 100
  .getResult()     // 100

Example 3

Input: 
actions = ["Calculator", "divide", "add", "getResult"], 
values = [[20], [0], [5], []]
Output: "Division by zero"
Explanation: 
new Calculator(20)  // 20
  .divide(0)        // Error: Division by zero

Constraints

- actions is a valid JSON array of strings
- values is a valid JSON array of numbers
- 2 <= actions.length <= 2 * 10^4
- 1 <= values.length <= 2 * 10^4 - 1
- actions[i] is one of "Calculator", "add", "subtract", "multiply", "divide", "power", and "getResult"
- First action is always "Calculator"
- Last action is always "getResult"

Approach 1: Class with Method Chaining

Intuition Create a Calculator class with an instance variable to store the result. Each arithmetic method updates this result and returns this to enable method chaining.

Steps

  • Initialize the Calculator with a starting value in the constructor
  • Implement each method (add, subtract, multiply, divide, power) to modify the result
  • Return this from each method to enable chaining
  • Implement getResult() to return the current result value
  • Handle division by zero by throwing an error
python
class Calculator:
    def __init__(self, value):
        self.result = value
    
    def add(self, value):
        self.result += value
        return self
    
    def subtract(self, value):
        self.result -= value
        return self
    
    def multiply(self, value):
        self.result *= value
        return self
    
    def divide(self, value):
        if value == 0:
            raise Exception("Division by zero")
        self.result /= value
        return self
    
    def power(self, value):
        self.result **= value
        return self
    
    def getResult(self):
        return self.result

Complexity

  • Time: O(1) for each operation
  • Space: O(1) - only storing the result
  • Notes: Simple and intuitive approach, most commonly used in real-world scenarios

Approach 2: Using Builder Pattern

Intuition Separate the calculation logic from the result storage using a builder-like pattern where operations are queued and executed when getResult is called.

Steps

  • Create a Calculator class that stores the initial value and a list of operations
  • Each method adds an operation to the queue instead of modifying the result directly
  • getResult() executes all operations in sequence and returns the final result
  • This allows for potential operation replay or modification before execution
python
class Calculator:
    def __init__(self, value):
        self.initial = value
        self.operations = []
    
    def add(self, value):
        self.operations.append(('add', value))
        return self
    
    def subtract(self, value):
        self.operations.append(('subtract', value))
        return self
    
    def multiply(self, value):
        self.operations.append(('multiply', value))
        return self
    
    def divide(self, value):
        if value == 0:
            raise Exception("Division by zero")
        self.operations.append(('divide', value))
        return self
    
    def power(self, value):
        self.operations.append(('power', value))
        return self
    
    def getResult(self):
        result = self.initial
        for op, value in self.operations:
            if op == 'add':
                result += value
            elif op == 'subtract':
                result -= value
            elif op == 'multiply':
                result *= value
            elif op == 'divide':
                result /= value
            elif op == 'power':
                result **= value
        return result

Complexity

  • Time: O(n) for getResult() where n is the number of operations, O(1) for other methods
  • Space: O(n) to store all operations
  • Notes: Useful when you need to replay or modify operations before execution, but uses more memory

Approach 3: Functional Approach with Closure

Intuition Use closures to encapsulate the state and return an object with methods that can access and modify the enclosed state, enabling method chaining without a traditional class.

Steps

  • Create a factory function that takes an initial value
  • Use a closure to maintain the result state
  • Return an object with methods that modify the enclosed state
  • Each method returns the object itself to enable chaining
python
def createCalculator(value):
    result = [value]
    
    class Calculator:
        def add(self, value):
            result[0] += value
            return self
        
        def subtract(self, value):
            result[0] -= value
            return self
        
        def multiply(self, value):
            result[0] *= value
            return self
        
        def divide(self, value):
            if value == 0:
                raise Exception("Division by zero")
            result[0] /= value
            return self
        
        def power(self, value):
            result[0] **= value
            return self
        
        def getResult(self):
            return result[0]
    
    return Calculator()

Complexity

  • Time: O(1) for each operation
  • Space: O(1) - only storing the result in closure
  • Notes: Functional programming style, provides encapsulation without classes, commonly used in JavaScript