我应该为每个不同的构造函数创建类,还是只为一个类创建两个构造函数?

问题描述

我是oop的新手,所以我只是在尝试一些东西。下面的问题只是一个虚构的问题,但是它可以帮助我更清楚地了解oop。

我正在编写一个计算器,只能将十进制数和二进制数相加。

所以我有一个名为Calculator的抽象类和两个子类-binaryCalculator和decimalCalculator

我的Calculator类中有两个抽象函数-add(),multiple()

现在的问题是,只有十进制add()函数确实将三个数字相加,其余的仅对两个数字执行。

所以现在我有点困惑,我应该在deciamCalculator类中创建两个构造函数还是应该只创建4个单独的子类-drciamAddingCalculator,decimalMultiplyingCalculator,binaryAddingCalculator和 binaryMultiplyingCalculator

解决方法

我也不明白为什么十进制计算器需要3个数字,但是一种可能的方法是让add()multiply()取任意数量的数字并将它们全部相加/相乘

Javacript示例:

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);
  }
}

请注意,这些方法可以是static,因此我们已经开始质疑为什么这是一个类以及该类的实例代表什么。

如果实例已将以前的数字存储为属性,则add()multiply()应该仅使用一个数字,并且应是void的方法,用于修改储值。

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

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

除了经典继承之外,还有很多方法可以考虑这一点。如果不想,根本不需要使用继承。

也许BinaryOperationsDecimalOperations中的一个被传递到Calculator的构造函数中并存储为实例变量this.operations

现在,Calculator类的唯一职责是存储滚动汇总并在调用操作时对其进行更新。它可以具有clear()undo()之类的方法。它不知道实际的数学运算,因为它将其委托给this.operations.add()。请注意,Operations接口在这里本质上是static,因此有进一步思考的空间。

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);
  }
}

如果这是一个交互式计算器,请考虑调用操作的顺序。您不只是在调用带数字的add方法,对吗?您将先按添加按钮,然后输入数字(一次输入一位数字),然后按等于按钮。在按下equals之前,不会进行任何数学运算,并且计算器需要存储有关按下了哪个数字和哪个操作的知识。

因此,在这种情况下,我们可能会传入一个Operations处理程序数组,其中一个操作具有一个Operation或一个,而不是为每个操作都传递一个带有方法的key对象。 symbol(在存储最后按下的按钮时使用)和callback,在适当的时候调用。

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

我可以继续,但是那应该足够让我思考。