区分用于货币的BigDecimal和用于百分比的BigDecimal

3

我在我的应用程序中使用 BigDecimal 来处理 货币百分比。但是,我需要一种区分两者用法的方法(用于呈现它们,例如,在 JTable 中)。因此,我的初始想法是编写两个类,这两个类的行为与 BigDecimal 完全相同,以便我可以对它们进行 instanceof 测试。所以我写了这段代码:

DollarValue.java:

import java.math.BigDecimal;

public class DollarValue extends BigDecimal {

}

PercentValue.java:

import java.math.BigDecimal;

public class PercentValue extends BigDecimal {

}

然而,为了使用构造函数(因为它们不能被继承),您需要手动覆盖每个构造函数。因此,DollarValue.java 变成了一个怪物:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;

public class DollarValue extends BigDecimal {

    public DollarValue(char[] in, int offset, int len) {
        super(in, offset, len);
    }
    public DollarValue(char[] in, int offset, int len, MathContext mc) {
        super(in, offset, len, mc);
    }
    public DollarValue(char[] in) {
        super(in);
    }
    public DollarValue(char[] in, MathContext mc) {
        super(in, mc);
    }
    public DollarValue(String val) {
        super(val);
    }
    public DollarValue(String val, MathContext mc) {
        super(val, mc);
    }
    public DollarValue(double val) {
        super(val);
    }
    public DollarValue(double val, MathContext mc) {
        super(val, mc);
    }
    public DollarValue(BigInteger val) {
        super(val);
    }
    public DollarValue(BigInteger val, MathContext mc) {
        super(val, mc);
    }
    public DollarValue(BigInteger unscaledVal, int scale) {
        super(unscaledVal, scale);
    }
    public DollarValue(BigInteger unscaledVal, int scale, MathContext mc) {
        super(unscaledVal, scale, mc);
    }
    public DollarValue(int val) {
        super(val);
    }
    public DollarValue(int val, MathContext mc) {
        super(val, mc);
    }
    public DollarValue(long val) {
        super(val);
    }
    public DollarValue(long val, MathContext mc) {
        super(val, mc);
    }
}

但更糟糕的是,在实现过程中,这并没有起作用,因为我经常使用静态的BigDecimal代码。举个例子:

public static void main(String[] args) {
    DollarValue dollars = DollarValue.ONE;
    DollarValue dollars2 = DollarValue.valueOf(25);
}

会抛出错误,因为DollarValue.ONE实际上是一个BigDecimal,而不是DollarValueDollarValue#valueOf()也返回一个BigDecimal

所以现在我没有任何主意。有什么最简单的方法可以区分我尝试实现的同一类的两个实现?这似乎是一个简单的问题...

编辑:任何允许我在渲染器中自动区分两者的解决方案也可以。例如,我需要将值提供给JTable,并且JTable显示货币符号$或百分比符号%


2
一个百分比就是一个数除以另一个数,再乘以100。你需要特殊的类来实现吗? - Robert Harvey
1
我强烈建议使用Joda-Money库来处理货币问题,而不是自己试图重复造轮子。处理货币问题是一个常见而棘手的问题。让其他人为你解决它吧。 - dimo414
2
在这里,尽量使用封装而不是继承。 - nanofarad
通常像Eclipse这样的IDE可以为您自动生成大量代码。 - arshajii
@arshajii,我忘了那个。在Netbeans中生成那段代码非常麻烦... - ryvantage
显示剩余8条评论
2个回答

1
使用组合而非继承。所有算术运算都应使用BigDecimal完成,但是有两个类,每个类都有一个以BigDecimal为参数的构造函数和一个返回BigDecimal的getValue方法。
代码看起来可能会更加复杂:
DollarValue dollars = new DollarValue(BigDecimal.ONE);
DollarValue dollars2 = new DollarValue(BigDecimal.valueOf(25));
DollarValue sum = new DollarValue(dollars.getValue().add(dollars2.getValue()));

如果某个类有几个非常常见的操作,请直接在该类中实现。例如,DollarValue 可以具有以下内容:
public DollarValue sum(DollarValue other) {
  return new DollarValue(getValue().add(other.getValue()));
}

不要在子类的行为与继承类不完全相同时使用继承(这违反了LSP规则)- 这是非常糟糕的做法。 - Alexey Malev

1
我强烈建议使用Joda-Money库来处理货币,而不是试图自己重新发明轮子。处理货币是一个常见且棘手的问题。让其他人为您解决它。
向项目添加新依赖项总是有点令人沮丧,但当涉及到提供明显但难以实现的核心实用程序库时,这应该是一个不言而喻的选择。一些其他关键的库包括:
  • Guava - 这绝对应该是现代Java代码库的一部分。提供的实用程序和新集合是不可替代的宝贵资源。
  • Joda-Time(除非您使用Java 8)- 像货币一样,时间是一种非常棘手的数据结构,需要正确表示(正如Java长期存在的Calendar和相关类所证明的那样),而Joda-Time提供了一个强大而深思熟虑的接口。

还有许多其他值得使用的库,但如果您不使用这三个库,则真的会犯错误。虽然从技术上讲它们是“非标准”的,但就像您所指出的那样,它们是如此普及,以至于它们离Java开发人员的工具箱的概念预期并不远。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接