【问题标题】:Should I create classes for each different constructor or should i just create two constructor for one class?我应该为每个不同的构造函数创建类还是应该只为一个类创建两个构造函数?
【发布时间】:2021-02-03 19:51:03
【问题描述】:

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

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

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

我的计算器类中有两个抽象函数-add()、multiply()

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

所以现在我有点困惑,我应该在 deciamCalculator 类中创建两个构造函数,还是应该只创建 4 个单独的子类 - drciamAddingCalculator、decimalMultiplyingCalculator、binaryAddingCalculator 和 二进制乘法计算器

【问题讨论】:

  • 十进制计算器为什么要取 3 个数字?
  • 不管怎样,有时候单独构建东西然后看看你是否能找到一个共同的抽象会更容易。从BinaryCalculatorDecimalCalculator 开始,找到共同点,看看是否可以将它们抽象为策略或其他内容。

标签: oop constructor solid-principles single-responsibility-principle open-closed-principle


【解决方案1】:

我也不明白为什么十进制计算器需要 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 方法,对吗?您可以先按添加按钮,然后输入数字(一次一位),然后按等号按钮。在按下等于之前不会进行任何数学运算,并且计算器需要存储关于按下了哪个数字和哪个操作的知识。

因此,在这种情况下,不是为每个操作传入一个带有方法的Operations 对象,而是传入一个Operation 处理程序数组,其中一个操作有一个keysymbol(我们在存储最后按下的按钮时使用)和 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

我可以继续,但这应该足够思考了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    相关资源
    最近更新 更多