数字系统类的继承层次结构 [英] Inheritance hierarchy for number system classes
问题描述
对于数学表达式的符号表示,我正在尝试构建数字系统类的层次结构。
For symbolic representation of mathematical expressions, I am trying to build a hierarchy of number system classes.
除了 Integer
和 Real
,我还需要类似 Rational
和 Complex
。我希望所有这些类能够相互无缝地互操作。
In addition to Integer
and Real
, I also need classes like Rational
and Complex
. I want all of these classes to inter-operate seamlessly with each other.
例如。将 Complex
数字添加到 Integer
将提供 Complex
数字等。
e.g. Adding a Complex
number to an Integer
would give a Complex
number etc.
我做了所有这些来实现 Number
界面。 (NOT java.lang.Number
)
I made all of them to implement the Number
interface. (NOT java.lang.Number
)
为了能够添加不同类型的数字,我尝试制作层次结构如下所示。
For being able to add numbers of different types, I tried making hierarchy like following.
整数
extendsRational
extendsReal
extendsComplex
Integer
extendsRational
extendsReal
extendsComplex
- 这使得
整数
不必要地存储虚部等。这种开销是不受欢迎的。 - 同样允许访问
Integer
的虚部。似乎不合适。 - This makes an
Integer
to unnecessarily store imaginary part etc. This overhead is undesired. - Also allowing access to imaginary part of an
Integer
seems improper.
任何人都可以建议更好的设计,避免开销并且仍然可以进行互操作吗?
Can anyone suggest a better design where overhead is avoided and interoperation is still possible?
推荐答案
我在这里看不到问题。实数是一个复数,整数是实数。复数可以表示为 a + bi
,整数是一个复数,这样 a
是一个整数, b = 0
。所以每个整数都有 b
,它等于0.
I don't see a problem here. Real number is a complex number, integer is a real number. Complex number can be expressed as a + bi
and an integer is a complex number, such that a
is an integer and b = 0
. So every integer has b
and it is equal to 0.
但是你可以考虑使用组合(和接口)过继承:
You may however consider using composition (and interfaces) over inheritance:
interface Complex {
Real a();
Real b();
}
interface Real extends Complex {
@Override
default Real b() {
return new Integer(0);
}
}
class Integer implements Real {
public Integer(int value) {
// ...
}
@Override
public Real a() {
return this;
}
// ...
}
这种方法的缺点是 Integer
类可以覆盖 b()
方法,所以也许继承会更好,因为你可以在方法上使用 final
关键字:
The disadvantage of this approach is that Integer
class can override b()
method, so maybe inheritance would be better, because you can use final
keyword on the method:
abstract class Complex {
abstract Real a();
abstract Real b();
}
abstract class Real extends Complex {
@Override
public final Real b() {
return new Integer(0);
}
}
class Integer extends Real {
public Integer(int value) {
// ...
}
@Override
public Real a() {
return this;
}
// ...
}
我自己试图对它进行建模,我在下面提出了这个可怕的代码。由于以下问题,我不高兴:
I have tried to model it myself and I came up with this terrible code below. I am not happy about it, because of the following problems:
-
界面
-InterfaceImpl
antipattern -
IntegerNumber
包含等方法realPart()
或numerator()
和denominator()
- 一些数字(复杂和理性)使用其他数字,而其他数字(实数和整数)使用Java原语
Interface
-InterfaceImpl
antipatternIntegerNumber
has methods such asrealPart()
ornumerator()
anddenominator()
- some numbers (complex and rational) use other numbers, while others (real and integer) use Java primitives
代码:
public class Test {
public static void main(String[] args) {
ComplexNumber complexOne = new ComplexNumber(new RealNumber(1.25), new RealNumber(3));
ComplexNumber complexTwo = new ComplexNumber(new RealNumber(7), new RealNumber(18.875));
System.out.println("adding two complex numbers:");
System.out.println(complexOne.add(complexTwo));
RealNumber realOne = new RealNumber(15.125);
RealNumber realTwo = new RealNumber(7.375);
System.out.println("adding two real numbers:");
System.out.println(realOne.add(realTwo));
System.out.println(realTwo.add(realOne));
System.out.println("adding complex and real number:");
System.out.println(complexOne.add(realOne));
System.out.println(realOne.add(complexOne));
RationalNumber rationalOne = new RationalNumber(new IntegerNumber(1), new IntegerNumber(2));
RationalNumber rationalTwo = new RationalNumber(new IntegerNumber(1), new IntegerNumber(3));
System.out.println("adding two rational numbers:");
System.out.println(rationalOne.add(rationalTwo));
IntegerNumber integerOne = new IntegerNumber(6);
IntegerNumber integerTwo = new IntegerNumber(7);
System.out.println("adding two integers:");
System.out.println(integerOne.add(integerTwo));
System.out.println("adding real number and integer:");
System.out.println(integerOne.add(realOne));
System.out.println(realOne.add(integerOne));
System.out.println("adding complex number and integer:");
System.out.println(integerOne.add(complexOne));
System.out.println(complexOne.add(integerOne));
}
}
// interfaces
interface Complex {
Real realPart();
Real imaginaryPart();
default Complex add(Complex other) {
return new ComplexNumber(
this.realPart().add(other.realPart()),
this.imaginaryPart().add(other.imaginaryPart())
);
}
}
interface Real extends Complex {
double asDouble();
@Override
default Real imaginaryPart() {
return new IntegerNumber(0);
}
default Real add(Real other) {
return new RealNumber(this.asDouble() + other.asDouble());
}
}
interface Rational extends Real {
Integer numerator();
Integer denominator();
@Override
default Real realPart() {
return new RealNumber(1.0d * numerator().asInt() / denominator().asInt());
}
@Override
default double asDouble() {
return realPart().asDouble();
}
default Rational add(Rational other) {
return new RationalNumber(
this.numerator().multiply(other.denominator()).add(this.denominator().multiply(other.numerator())),
this.denominator().multiply(other.denominator())
);
}
}
interface Integer extends Rational {
int asInt();
@Override
default Integer numerator() {
return new IntegerNumber(asInt());
}
@Override
default Integer denominator() {
return new IntegerNumber(1);
}
default Integer add(Integer other) {
return new IntegerNumber(this.asInt() + other.asInt());
}
default Integer multiply(Integer other) {
return new IntegerNumber(this.asInt() * other.asInt());
}
}
// implementations
class ComplexNumber implements Complex {
private final Real realPart;
private final Real imaginaryPart;
public ComplexNumber(Real realPart, Real imaginaryPart) {
this.realPart = realPart;
this.imaginaryPart = imaginaryPart;
}
@Override
public Real realPart() {
return realPart;
}
@Override
public Real imaginaryPart() {
return imaginaryPart;
}
@Override
public String toString() {
return String.format("%s + %si", realPart, imaginaryPart);
}
}
class RealNumber implements Real {
private final double value;
public RealNumber(double value) {
this.value = value;
}
@Override
public Real realPart() {
return this;
}
@Override
public double asDouble() {
return value;
}
@Override
public String toString() {
return "" + value;
}
}
class RationalNumber implements Rational {
private final Integer numerator;
private final Integer denominator;
public RationalNumber(Integer numerator, Integer denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
@Override
public Integer numerator() {
return numerator;
}
@Override
public Integer denominator() {
return denominator;
}
@Override
public String toString() {
return String.format("%s/%s", numerator, denominator);
}
}
class IntegerNumber implements Integer {
private final int value;
public IntegerNumber(int value) {
this.value = value;
}
@Override
public int asInt() {
return value;
}
@Override
public String toString() {
return "" + value;
}
}
我想知道接口是否应该是实现方法的抽象类是final。最后,我认为最好只使用简单继承并忽略每个整数都有一个虚部的字段的事实。
I am wondering whether interfaces should be abstract classes with implemented methods being final. In the end, I think it may be better to just go with simple inheritance and ignore the fact that every integer will have a field for imaginary part.
我希望这会给你一些想法。
I hope this will give you some ideas.
这篇关于数字系统类的继承层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!