我也不明白为什么十进制计算器需要 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;
}
}
除了经典继承之外,还有很多方法可以考虑这个问题。如果您不想,则根本不需要使用继承。
也许BinaryOperations 和DecimalOperations 之一被传递到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 处理程序数组,其中一个操作有一个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
我可以继续,但这应该足够思考了。