0

I'm coding a simple currency exchange app. I have parent class Currency which contains the method convertTo and 3 subclasses which represents some specific currencies. What I want to do is to make that convertTo method universal so I can invoke it on the subclass and return an object of another subclass.

My best idea is to use generics but while creating a method which should return generic type I encountered an error which says I couldn't initialize raw type directly. The question is how can I initialize this type in parent class method? Please note I did not provide the whole code, some methods are skipped

public class Currency implements CurrencyUnit {
    private CurrencyName name;
    private BigDecimal amount;
    private BigDecimal rate;
    private BigDecimal spread;

    public Currency() {}

    public Currency(BigDecimal amount) {
        if(BigDecimal.ZERO.compareTo(amount) > 0) {
            throw new IllegalArgumentException("Amount can't be negative.");
        }
        this.amount = amount.setScale(SCALE, ROUNDING_MODE);
    }

//method that should return subclass object
//currencyToConvert is Enum type
    public Currency convertTo(CurrencyName currencyToConvert) throws IOException {
        if (currencyToConvert.equals(this.getCurrencyName())) {
            throw new IllegalArgumentException("Can't convert to same currency.");
        }

        String currencyUrl = "https://api.exchangeratesapi.io/latest%s%s";
        String baseCurrencyUrl = String.format(currencyUrl, "?base=", this.getCurrencyName().toString());
        RatesAPI ratesAPI = new RatesAPI(baseCurrencyUrl);
        return new Currency(this.amount.multiply(ratesAPI.rateFromAPI(currencyToConvert.toString())));
    }
}

//example of subclass (the other subclass for Dollar is basically the same only with currency name difference)
public class Euro extends Currency implements CurrencyUnit {
    private final CurrencyName eur = CurrencyName.EUR;

    public Euro() {}

    public Euro(BigDecimal amount) {
        super(amount);
    }

    public Euro(BigDecimal amount, BigDecimal rate, BigDecimal spread) {
        super(amount, rate, spread);
    }

    @Override
    public CurrencyName getCurrencyName() {
        return eur;
    }

//and the example of Main method
public class Main {
    public static void main(String[] args) throws IOException {

        Currency eur = new Euro(BigDecimal.ONE);
        Currency usd = new Dollar(BigDecimal.ONE);

        System.out.println(eur);

        usd = eur.convertTo(CurrencyName.USD);
        System.out.println(usd);

What I want to achieve is to invoke convertTo method on Euro class object so that method return e.g. Dollar class object. As I mentioned before the most elegant solutions for me seems to use generic types. When I created class Currency<T> and invoked method on e.g Dollar and as a method parameter, I used Currency<T> object I encountered exception created "Can't convert to same currency" which seems logical. I'm not looking for a direct answer to my question, just some guidance because those generics are quite complicated to me. I tried to search for the answer in web, in fact, I found this but it shows how to return object on which the method was invoked.

Tlaloc-ES
  • 4,825
  • 7
  • 38
  • 84
novice
  • 41
  • 4
  • [The factory pattern](https://www.tutorialspoint.com/design_pattern/factory_pattern) could be of some use to you. – Austin Schaefer Jul 26 '19 at 09:51
  • 1
    Do you really need currencies to have their own classes? Can't they simply be instances of `Currency`? – Andy Turner Jul 26 '19 at 09:52
  • 1
    By the way: your `Currency` class isn't modelling a currency (which to me connotes EUR, GBP, USD), it is modelling an amount *of* a currency (10EUR, 10GBP, 10USD). – Andy Turner Jul 26 '19 at 09:58
  • @AndyTurner maybe it's because I skipped some of the code. In `Currency ` there are two other constructors, one of them also include informations about spread and rate but it's rather irrelevant to the problem. I think they could be just `Currency` instances. In fact above code works fine in matter of computing, the only problem I have right now is to define names of newly created instances of currencies. Right now they displaying as `null`. Don't you think if I make specific currencies objects the code will be more universal? – novice Jul 26 '19 at 10:11
  • @AustinSchäfer I'll have a look at it, thanks – novice Jul 26 '19 at 10:12
  • @novice "the only problem I have right now is to define names of newly created instances of currencies. " could that be because you're not setting the `name` field in the base class? – Andy Turner Jul 26 '19 at 10:39
  • @novice "Don't you think if I make specific currencies objects the code will be more universal?" No. Quite the opposite. If you make specific currencies, you can't create instances of new/additional currencies. – Andy Turner Jul 26 '19 at 10:41
  • @AndyTurner I followed your advice and changed only the names instead of creating new objects of specific currencies. Thank you for your help – novice Jul 27 '19 at 22:14

0 Answers0