开发者

Extending BigDecimal?

开发者 https://www.devze.com 2023-03-15 03:37 出处:网络
I\'ve a fair bit of code using BigDecimal Class and I hate the clumsiness of the interface. I\'ve alleviated the pain of using BigDecimals with integers by creating a helper class with static methods

I've a fair bit of code using BigDecimal Class and I hate the clumsiness of the interface.

I've alleviated the pain of using BigDecimals with integers by creating a helper class with static methods with the following methods:

compare(BigDecimal first, int second)
divide(BigDecimal dividend, BigDecimal divisor, int scale)
divide(BigDecimal dividend, in开发者_运维知识库t divisor, int scale)
divide(int divident, int divisor, int scale)
multiply(BigDecimal first, BigDecimal second, int scale)
multiply(BigDecimal first, int second, int scale)
multiply(int first, int second, int scale)
zeroPad(BigDecimal value, int totalLength, int scale)

That's all I need for now and the code is a little more readable than before. However, I read that static methods are a "bad" thing and that they don't follow OO-principles.

If I extend BigDecimal however, I'd define a new type and thus I'd have to re-define all methods to wrap them with my object or I won't be able to use the results with the augmented methods. It doesn't seem a smart thing to do.

How would you approach this problem?


I would do it exactly as you have!

All design decisions of this type must be based on a wish to make the code more maintainable for the next programmer that will take over the code after you. Which is why we make O-O design and component based development in the first place.

But given the syntax of Java, it is really difficult to make an API for math-based expressions. I have two problems with the current BigInteger API:

  • it is not very close to the usual math-notation
  • it is asymmetric for symmetric operators like add and multiply

[Operator-overload is one of the few features of C++, I miss in Java]

Which is more readable?

BigInteger a = ...;
BigInteger b = ...;
BigInteger c = divide(a, b);

or

BigInteger a = ...;
BigInteger b = ...;
BigInteger c = a.divide(b);

Personally, I prefer the second version.

Worse is the cases where numbers of different base types are part of the same expression. E.g.

int a = ...;
BigInteger b = ...;
BigInteger c = divide(a, b);

or

int a = ...;
BigInteger b = ...;
BigInteger c = BigInteger.valueOf(a).divide(b);

Also consider the big differences in the notations from the small changes in the corresponding math notation:

  • (a-b)*c is translated to a.subtract(b).multiply(c) or multiply(subtract(a,b),c)
  • c*(a-b) is translated to c.multiply(a.subtract(b)) or multiply(c,subtract(a,b))

For me, it is easier to write and read the static method notation, than the "pure" O-O based notation.


Don't extend BigDecimal, use a wrapper class around it (like you have) or another framework like Commons Math.

Dfp looks similar to what you want - org.apache.commons.math.dfp.Dfp


Could you please clarify to me what do you mean exactly with "I'd define a new type and thus I'd have to re-define all methods to wrap them with my object or I won't be able to use the results with the augmented methods."?

  • If you need to use most of the methods from BigDecimal API, plus your own additional methods, then I'd suggest you inherit your custom class from BigDecimal. In this way, you do not need to define wrappers for the BigDecimal methods that already work fine for you. This scenario is the one where your custom class is a BigDecimal, plus something more.

  • If you need just a few methods from BigDecimal API, plus your own additional methods, then I'd suggest you do not derive from BigDecimal. Instead you use internally a BigDecimal, and you delegate to it some of the functionalities exposed by your custom API. This scenario is the one where your custom class has a BigDecimal, but it's not a BigDecimal.

Then in order to wrap a BigDecimal method to return your custom type:

With inhertance, you'd do something like the following:

@Override public MyBD divide(int second)
{
    return new MyBD( this.divide(second) );
}

With delegation (i.e. composition), you'd do:

public MyBD divide(int second)
{
    return new MyBD( _innerBigDecimal.divide(second) );
}

With static helper methods, you'd do:

public static BigDecimal divide(BigDecimal first, int second)
{
    return first.divide(second);
}


If you create a class that extends another class (i.e. BigDecimal in your case), the child class still has all properties of the parent (super) class. In your case, if you write:

public class UsableBigDecimal extends BigDecimal {
...
}

any UsableBigDecimal objects would still be instances of BigDecimal, since it's their superclass. You would be able to use them as you would any BigDecimal object, your static utility methods included.

That said, static utility methods are, in my opinion, quite acceptable as a way to share common code when dealing with core Java classes.


I would forget about this problem, and the original problem, and get used to the API of BigDecimal as it is. All you're doing is creating problems for yourself, as the existence of this question demonstrates.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号