Расширяете BigDecimal? - PullRequest
       25

Расширяете BigDecimal?

8 голосов
/ 25 июня 2011

У меня довольно много кода с использованием BigDecimal Class, и я ненавижу неуклюжесть интерфейса.

Я облегчил задачу использования BigDecimal s с целыми числами, создав вспомогательный класссо статическими методами со следующими методами:

compare(BigDecimal first, int second)
divide(BigDecimal dividend, BigDecimal divisor, int scale)
divide(BigDecimal dividend, int 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)

Это все, что мне нужно на данный момент, и код немного более читабелен, чем раньше.Тем не менее, я прочитал, что статические методы - это «плохая» вещь, и они не следуют ОО-принципам.

Однако если я расширю BigDecimal, я бы определил новый тип и, таким образом,придется переопределить все методы, чтобы обернуть их моим объектом, иначе я не смогу использовать результаты с расширенными методами.Это не кажется разумным.

Как бы вы подошли к этой проблеме?

Ответы [ 5 ]

5 голосов
/ 25 июня 2011

Я бы сделал это точно так же, как вы!

Все проектные решения этого типа должны основываться на желании сделать код более понятным для следующего программиста, который возьмет на себя код после вас. Вот почему мы в первую очередь делаем разработку O-O и разработку компонентов.

Но, учитывая синтаксис Java, действительно сложно создать API для математических выражений. У меня есть две проблемы с текущим API BigInteger:

  • это не очень близко к обычной математической записи
  • это асимметрично для симметричных операторов, таких как сложение и умножение

[Перегрузка оператора - это одна из немногих функций C ++, которую я пропускаю в Java]

Что является более читабельным?

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

или

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

Лично я предпочитаю вторую версию.

Хуже всего случаи, когда числа разных базовых типов являются частью одного и того же выражения. Э.Г.

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

или

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

Также рассмотрим большие отличия в обозначениях от небольших изменений в соответствующих математических обозначениях:

  • (a-b)*c переводится как a.subtract(b).multiply(c) или multiply(subtract(a,b),c)
  • c*(a-b) переводится как c.multiply(a.subtract(b)) или multiply(c,subtract(a,b))

Для меня проще написать и прочитать нотацию статического метода, чем «чистую» нотацию на основе O-O.

4 голосов
/ 25 июня 2011

Не расширяйте BigDecimal, используйте вокруг него класс-оболочку (как у вас) или другой фреймворк, например Commons Math.

Dfp выглядит так, как вы хотите - org.apache.commons.math.dfp.Dfp

2 голосов
/ 25 июня 2011

Не могли бы вы уточнить мне, что именно вы имеете в виду под "Я бы определил новый тип, и, таким образом, мне пришлось бы переопределить все методы, чтобы обернуть их моим объектом, или я не будувозможность использовать результаты с расширенными методами. "?

  • Если вам нужно использовать большинство методов из API BigDecimal, плюс ваши собственные дополнительныеметоды, тогда я бы посоветовал вам наследовать свой собственный класс от BigDecimal.Таким образом, вам не нужно определять оболочки для методов BigDecimal, которые уже отлично работают для вас.В этом сценарии пользовательский класс представляет собой BigDecimal, плюс еще кое-что.

  • Если вам нужно всего лишь несколько методов из BigDecimal API, плюс ваши собственные дополнительные методы, то я бы предложил вам не наследоватьот BigDecimal.Вместо этого вы используете для внутреннего использования BigDecimal, и вы делегируете ему некоторые функции, предоставляемые вашим пользовательским API.В этом сценарии ваш пользовательский класс имеет BigDecimal, но это не BigDecimal.

Затем, чтобы обернуть метод BigDecimal, чтобы вернуть ваш пользовательский тип:

С наследованием вы бы сделали что-то вроде следующего:

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

С делегированием (то есть составом) вы бы сделали:

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

Сстатические вспомогательные методы:

public static BigDecimal divide(BigDecimal first, int second)
{
    return first.divide(second);
}
0 голосов
/ 25 июня 2011

Я бы забыл об этой проблеме и первоначальной проблеме и привык бы к API BigDecimal как таковой. Все, что вы делаете, это создает проблемы для себя, как показывает существование этого вопроса.

0 голосов
/ 25 июня 2011

Если вы создаете класс, который расширяет другой класс (например, BigDecimal в вашем случае), дочерний класс по-прежнему имеет все свойства родительского (супер) класса.В вашем случае, если вы напишите:

public class UsableBigDecimal extends BigDecimal {
...
}

, любые объекты UsableBigDecimal все равно будут экземплярами BigDecimal, поскольку это их суперкласс.Вы сможете использовать их так же, как и любой объект BigDecimal, включая ваши статические служебные методы.

При этом статические служебные методы, на мой взгляд, вполне приемлемы для обмена общим кодом при работе сосновные классы Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...