Параметры нескольких типов в методах Java, включая существующие классы и примитивные типы данных - PullRequest
6 голосов
/ 24 сентября 2019

У меня есть класс с кодом, подобным следующему, где я хочу, чтобы было тривиально использовать любой класс / тип, который представляет число.Я обнаружил, что определяю большое количество методов, таких как следующие:

public class Range {
    private BigDecimal inferior = new BigDecimal(0);
    private BigDecimal superior = new BigDecimal(1);

    public Range(BigDecimal inferior, BigDecimal superior) {
        if (inferior.compareTo(superior) == -1) {
            this.inferior = inferior;
            this.superior = superior;
        }
    }
    public Range(int inferior, int superior) {
        this(new BigDecimal(inferior), new BigDecimal(superior));
    }
    public Range(Integer inferior, Integer superior) {
        this(new BigDecimal(inferior), new BigDecimal(superior));
    }
    public Range(float inferior, float superior) {
        this(new BigDecimal(inferior), new BigDecimal(superior));
    }
    public Range(double inferior, double superior) {
        this(new BigDecimal(inferior), new BigDecimal(superior));
    }
}

Я даже не написал каждую возможную комбинацию!Например, тот, который принимает float и double, или int и BigDecimal.

Как этого можно достичь чистым способом, чтобы были параметры, допустимые для нескольких классов / типов данных, которые ужепредопределенные или даже примитивы?Я рассмотрел адаптеры и прокси-серверы, но я регулярно не понимаю объяснения и не могу понять, соответствуют ли они моему варианту использования, и если да, то как - на этот вопрос уже можно было ответить на SO, но если так, то хотя быЯ хотел бы узнать, может ли кто-нибудь объяснить мне это в соответствии с этим конкретным примером.

Ответы [ 3 ]

3 голосов
/ 24 сентября 2019

Используйте шаблон Builder .Создайте вложенный статический класс, который принимает каждый из отличительных типов данных для каждого из двух чисел.Примитивные типы от byte до long будут расширены до long и float до double.BigInteger с может быть преобразовано в BigDecimal с, и BigDecimal ссылки будут скопированы.

public static class Builder {
    BigDecimal first;
    BigDecimal second;

    public void setFirst(long value) { first = new BigDecimal(value); }
    public void setFirst(double value) { first = new BigDecimal(value); }
    public void setFirst(BigInteger value) { first = new BigDecimal(value); }
    public void setFirst(BigDecimal value) { first = value; }
    public void setSecond(long value) { second = new BigDecimal(value); }
    public void setSecond(double value) { second = new BigDecimal(value); }
    public void setSecond(BigInteger value) { second = new BigDecimal(value); }
    public void setSecond(BigDecimal value) { second = value; }
    public Range build() {
        if (first == null || second == null) {
            throw new IllegalArgumentException("Must supply both values.");
        }
        return new Range(first, second);
    }
}

Шаблон Builder позволяет выполнить проверку перед построением требуемого объекта и обходит «взрыв конструктора»это произойдет при попытке охватить все возможные комбинации.С n возможных типов у вас есть 2 * n методов установки конструктора вместо n 2 конструкторов.

Iвключенный long, хотя он может быть расширен до double юридически, из соображений точности, поскольку существуют очень высокие значения типа long, которые нельзя точно представить как double s .

Затем ваш конструктор становится:

public Range(BigDecimal first, BigDecimal second) {
    if (first.compareTo(second) < 0) {
        this.inferior = first;
        this.superior = second;
    }
    else {
        this.inferior = second;
        this.superior = first;
    }
}

Я изменил == -1 на < 0 в соответствии с контрактом compareTo и добавил случай else, который их переключаетесли нужно.

2 голосов
/ 24 сентября 2019

Используйте класс Number:

public Range(Number inferior, Number superior)

Integer, Long, Double - все они являются подклассами Number.

В качестве альтернативы используйте дженерики:

public class Range<T> {
    private T inferior;
    private T superior;

    public Range(T inferior, T superior) {
        this.inferior = inferior;
        this.superior = superior;
    }
}

Использование:

Range<Long> rangeLong = new Range<>(0L, 1000000000L);
Range<Double> rangeDouble= new Range<>(0d, 457.129d);
0 голосов
/ 24 сентября 2019

Из документов BigDecimal(String):

Как правило, это предпочтительный способ преобразования float или double в BigDecimal, поскольку он не страдает отнепредсказуемость конструктора BigDecimal(double).


Примите Number, используйте String.valueOf для преобразования в строку, затем перейдите в BigDecimal:

public class Range {
    private BigDecimal inferior;
    private BigDecimal superior;

    public Range(Number inferior, Number superior) {
        this.inferior = new BigDecimal(String.valueOf(inferior));
        this.superior = new BigDecimal(String.valueOf(superior));
    }
}

Любые классы, расширяющие Number, включая введенные вами новые типы, будут автоматически поддерживаться.

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