我在玩一个没有例外的编程的想法,使用沃德·坎宁安的特殊价值和无意义的行为模式的组合。
假设我有一个接口分数,用来表示任何数量,可以用一组运算除以2个其他数量来表示:
interface Fraction {
Fraction add(Fraction f);
Fraction subtract(Fraction f);
Fraction multiply(Fraction f);
Fraction divide(Fraction f);
}
现在,这个接口将有两个主要实现:a)simplefraction,其中分母不是0;b)未分母,分母为0。两者都将由工厂创建:
public final class SimpleFraction implements Fraction {
private final int numerator, denominator;
private SimpleFraction(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
// interface method implementations
}
public final class UndefinedFraction implements Fraction {
private final int numerator;
private UndefinedFraction(int numerator) {
this.numerator = numerator;
}
// interface method implementations
}
undefinedfraction将是一个具有无意义行为的异常值:它的每个操作都应返回一个undefinedfraction。更重要的是,如果它被用作任何其他分数运算的参数,结果也应该是一个未定义的分数:
FractionFactory factory = new FractionFactory();
Fraction simple = factory.fromNumeratorAndDenominator(420, 10);
Fraction undefined = factory.fromNumeratorAndDenominator(42, 0);
assertEquals(simple.add(undefined), undefined);
assertEquals(undefined.add(simple), undefined);
assertEquals(undefined.add(undefined), undefined);
我怎样才能在涉及未定义分形的运算中强制执行这种变换?我正在寻找基于多态性的选项(例如,它们不应该依赖于布尔检查)。
1条答案
按热度按时间k2fxgqgv1#
问题是关联性。
术语:给定“a/b”,我们称a为lhs(左侧),b为rhs,“/”为运算符,而“divide”为运算。LH和RH都是“操作数”。
问题是:假设我们创建了两种未定义的味道。我们有“red undefined”和“green undefined”,并且我们坚持相同的定义:任何lhs和/或rhs为“red undefined”的操作都应该产生“red undefined”。
同样的规则也适用于“green undefined”:任何lhs和/或rhs为“green undefined”的操作都应为“green undefined”,而不考虑其他操作数的值和操作。
不幸的是,这一定义模棱两可:
是红色的,还是绿色的?谁有优先权?
这个问题应该强调,你的问题没有简单/明显的答案!
回到“a/b”——您所做的(在面向对象语言中这是很难避免的)是定义操作数上可用的操作。它是一个有除法的a。并不是说“divide”这个概念是一个对象,它有一个接受2个参数的方法。换言之,你有:
而不是这个:
基本设计
a.divide(b)
work固有地将“left”关联起来(比如,“a”决定了divide的实现,b正好代表了right),而不将“right”关联起来,因为java就是这样定义的。问题是,这里不需要左关联性:如果“b”未定义而“a”未定义,则需要“b”重写并控制操作。
但是你不能这样做,因为前面提到的红/绿未定义的问题,没有一个简单的语言建议可以做到这一点。
根本的问题是您已经定义了一个操作(分数除法),它应该根据操作本身而不是任何一个操作数来定义。因此,
fractionNumberSystem.divide(a, b)
更有意义;您可以在那里编写“如果任一操作数未定义,则结果未定义”的代码,甚至可以引入一个系统,询问每个操作数是否要负责该操作,并为每个操作数提供一个优先级层次结构,数字系统将选择报告其具有最高优先级的操作数,让它做手术。幸运的是,你可以
a.divide(b)
归结起来:现在numbersystem.divide可以做任何你想做的事情。“除法运算首先与未定义相关联,无论未定义的哪一边在哪一边”的概念可以在numbersystem的除法方法中编程。或者,你可以让它更“可插拔”,找到解决红/绿问题的方法(当双方都想控制操作时,你如何决定哪一方“获胜”?是红色的。添加(绿色)红色还是绿色?),不管你怎么想。也许通过检查所涉及的分数是否是“operationcontrollingfraction”(您将创建的子类型)的示例,并使operationcontrollingfraction类型
radd
方法(右关联add)以及int priority()
方法。注意:提示:
add
是个坏名声。plus
效果更好。a.add(b)
这意味着a
.a.plus(b)
表示a保持不变,并返回一个新值。对,BigInteger
朋友的名字都不好。它发生了;那些api都很老了,我不认为为了保持一致而延续明显的设计错误是个好主意,因为设计错误已经足够严重了。