Should I create classes for each different constructor or should i just create two constructor for one class?

37 views Asked by At

I am new to oop.so i am just experimenting some stuffs.The below problem is just a made up problem but it would help me to understand oop more clearly.

I am coding to make a calculator which can only add and multiply deciaml number and binary number.

So I have an abstract class named Calculator and two child classes- binaryCalculator and decimalCalculator

There are two abstract function in my Calculator class- add(), multiply()

Now the problem is, only decimal add() function does add three numbers altogether,the rest perform only on two numbers .

So now I am kinda confused,should i make two constructor in deciamCalculator class or should i just create 4 individual child classes - drciamAddingCalculator, decimalMultiplyingCalculator, binaryAddingCalculator and binaryMultiplyingCalculator

1

There are 1 answers

0
Linda Paiste On

I'm also not understanding why the decimal calculator would need 3 numbers, but one possible approach is to have the add() and multiply() take an arbitrary amount of numbers and add/multiply them all together.

Javacript example:

class DecimalCalulator extends AbstractCalculator {
  add(...numbers: number[]): number {
    return numbers.reduce((sum, n) => sum + n);
  }
  multiply(...numbers: number[]): number {
    return numbers.reduce((product, n) => product * n);
  }
}

Note that these methods can be static, so already we start to question why this is a class an what an instance of this class represents.

If the instance has stored the previous number as a property, then add() and multiply() should take only one number and be void methods which modify the stored value.

class AbstractCalculator {
  protected total: number = 0;
  /*... */
}

class DecimalCalulator extends AbstractCalculator {
  add(number: number): void {
    this.total += number;
  }
  multiply(number: number): void {
    this.total *= number;
  }
}

There are a lot of ways to think about this beyond just classical inheritance. You don't need to use inheritance at all if you don't want to.

Perhaps one of BinaryOperations and DecimalOperations is passed into the constructor of a Calculator and stored as an instance variable this.operations.

Now the single responsibility of the Calculator class is to store a rolling total and update it when operations are called. It can have methods like clear() and undo(). It doesn't know about the actual math because it delegates that to this.operations.add(). Note that the Operations interface is essentially static here, so there's room to rethink this further.

interface Operations {
  add(...numbers: number[]): number;
  multiply(...numbers: number[]): number;
}

class Calculator {
  private total: number;
  private readonly operations: Operations;

  constructor( operations: Operations ) {
    this.total = 0;
    this.operations = operations;
  }

  clear(): void {
    this.total = 0;
  }

  add( number: number ): void {
    this.total = this.operations.add(this.total, number);
  }

  multiply( number: number ): void {
    this.total = this.operations.multiply(this.total, number);
  }
}

If this is an interactive calculator, think about what order the actions are called in. You're not just calling an add method with a number, right? You would press the add button first, then enter the number (one digit at a time), and then press the equals button. No math is done until equals is pressed, and the calculator needs to store knowledge of which number and which operation were pressed.

So in that case instead of passing in an Operations object with methods for each operation, perhaps we pass in an array of Operation handlers, where an operation has a key or a symbol (which we use when storing the last button pressed) and a callback to call when the time is right.

interface ButtonHandler {
  symbol: string;
  callback( previousValue: number, enteredValue: number ): number;
}

const DecimalAdd: ButtonHandler = {
  symbol: '+',
  callback: ( a, b ) => a + b,
} // this is a plain javascript object, not a class, but it implements out interface

I could go on, but that should be enough food for thought.