Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 存储货币汇率的设计_Java_Oop - Fatal编程技术网

Java 存储货币汇率的设计

Java 存储货币汇率的设计,java,oop,Java,Oop,我已经开始了一个新的信用管理项目,我已经到了必须处理货币兑换的地步。(例如欧元->美元)所以我做了一些头脑风暴,得出了以下结论: 货币是抽象的,每一种新货币都是一个接口的实现 构建了一个rate类,该类存储pair数组列表(我想到的是类似于euro,dollar,1.14->欧元对美元的汇率是1.14),并具有一些功能,如:货币汇率存储,正确汇率的查找器(它是一个函数,获取当前货币和新货币作为参数,并在列表上执行搜索,返回适当的货币)和一个实用函数,用于确定货币对的索引 现在,我在考虑性能。

我已经开始了一个新的信用管理项目,我已经到了必须处理货币兑换的地步。(例如欧元->美元)所以我做了一些头脑风暴,得出了以下结论:

  • 货币是抽象的,每一种新货币都是一个接口的实现
  • 构建了一个rate类,该类存储pair数组列表(我想到的是类似于euro,dollar,1.14->欧元对美元的汇率是1.14),并具有一些功能,如:货币汇率存储,正确汇率的查找器(它是一个函数,获取当前货币和新货币作为参数,并在列表上执行搜索,返回适当的货币)和一个实用函数,用于确定货币对的索引
现在,我在考虑性能。我相信我的设计包含一些冗余:如果我有欧元对美元,我就必须有美元对欧元。此外,我的存储(成对数组列表)对于更多的条目(假设100k)有多高的效率?我有什么替代方案? 我知道有很多数据结构,我真的不知道该选什么

现在,对于代码:

转换率等级:

package currency;

import javafx.util.Pair;
import loggers.ILogger;

import java.util.ArrayList;

public class ConversionRates implements IConversionRate {
    private ArrayList<Pair<Pair<String, String>, Double>> conversionRates;
    private ILogger log;


    public ConversionRates(ArrayList<Pair<Pair<String, String>, Double>> conversionRates, ILogger log) {
        this.conversionRates = conversionRates;
        this.log = log;
    }

    @Override
    public double find(ICurrency firstCurrency, ICurrency secondCurrency) {
        log.add("Performing rate identification");
        String first = firstCurrency.getId();
        String second = secondCurrency.getId();
        int index = searchPairs(first, second);
        Pair<Pair<String, String>, Double> selectedPair = conversionRates.get(index);
        double rate = selectedPair.getValue();
        return rate;
    }

    private int searchPairs(String first, String second) {
        Pair<String, String> pairContainingRate = new Pair<>(first, second);
        for (int index = 0; index < conversionRates.size(); index++) {
            if (conversionRates.get(index).getKey().equals(pairContainingRate)) {
                log.add("Successfully found target " + first + "/" + second);
                return index;
            }
        }

        log.add("Failed to find target " + first + "/" + second);
        return -1;
    }

    @Override
    public void add(Pair<Pair<String, String>, Double> newRate) {
        log.add("Added new rate " + newRate);
        conversionRates.add(newRate);
    }

    @Override
    public void update(ArrayList<Pair<Pair<String, String>, Double>> newRates) {
        log.add("Updated rates");
        conversionRates.clear();
        conversionRates.addAll(newRates);
    }

    @Override
    public void remove(Pair<Pair<String, String>, Double> redundantRate) {
        log.add("Removed rate " + redundantRate);
        conversionRates.remove(redundantRate);
    }
}
货币实施(我将只列出欧元,因为欧元完全相同):


我也想听听你对总体设计的看法。

事实上,肯特·贝克(Kent Beck)在他关于TDD的书中就此事进行了研究

我没有读到最后,但我记得在某个时候,他有
货币
抽象类,
总和
(或类似的东西)用于存储货币和
银行
。银行负责货币汇率

我不确定创建像
Dollar
Euro
这样的类是否是一个好方法。也许坚持使用
Money
并将货币保持在实例变量(KISS)中更容易。我想我希望货币完全由一个类处理(
Bank
ExchangeRate
或任何最适合你的东西)我会让
Money
实例不可变。所有的计算都是由
Sum
类进行的(或其他,重点是将逻辑从Money本身移开)


无论如何,也许你应该看看贝克的书。我很确定他设计得很好。

我认为你应该从更简单的角度开始。我不明白为什么要使用货币接口,尤其是在这种情况下,因为我不明白你的实现将需要不同的提供者。每个
货币都用一个符号和该货币的一组汇率

public class Currency {
    private final String symbol; 
    private final Set<ExchangeRate> rates = new HashSet<>();

    public Currency(String symbol) {
        this.symbol = symbol;
    }
    public BigDecimal convert(Currency currency, BigDecimal amount) {
        return findExchangeRate(currency).getRate().multiply(amount).setScale(2, RoundingMode.HALF_DOWN);
    }
    public String getSymbol() {
        return symbol;
    }
    public ExchangeRate findExchangeRate(Currency currency) {
        for(ExchangeRate rate: rates) {
            if ( rate.getCurrency().equals(currency)) {
                return rate;
            }
        }
        throw new IllegalArgumentException("Currency not found: " + currency);
    }
    public void setExchangeRate(ExchangeRate rate) {
        if ( rates.contains(rate) ) rates.remove(rate);
        rates.add(rate);
    }
    public boolean removeExchangeRate(ExchangeRate rate) {
        return rates.remove(rate);
    }
使用它非常简单

Currency usd = new Currency("USD");
Currency eur = new Currency("EUR");
usd.setExchangeRate(new ExchangeRate(eur, new BigDecimal("0.87540")));
eur.setExchangeRate(new ExchangeRate(usd, new BigDecimal("1.14233")));

BigDecimal myMoney = new BigDecimal("1000.00");
myMoney = usd.convert(eur, myMoney);
System.out.println("My Euros: " + myMoney);
myMoney = eur.convert(usd, myMoney);
System.out.println("My Dollars: " + myMoney);

请注意
BigDecimal
的用法。由于浮点和双精度的错误,这类或类似的操作对于货币计算总是必需的。您可以转换为
Long
Integer
并自己跟踪比例,但您将执行与
BigDecimal
类相同的操作

在考虑性能之前,您应该先考虑可读性。我不知道ArrayList可能包含什么。定义类、枚举,它们的名称清楚地显示它们所代表的内容。请注意,Java和Guava都不包括Pair类,因为它鼓励开发人员编写与您所拥有的代码类似的不可读代码e那里。第一对表示货币,双精度表示从第一个到第二个的实际汇率。然后定义并使用一个包含三个字段的CurrencyConversion类:CurrencySourceCurrency、CurrencyTargetCurrency、double conversionRate。它可读性更强。它可以包含实际计算转换的方法。它可以ontain是一种通过交换两种货币并反转汇率来创建反向货币转换的方法。它可以在构建时验证汇率的有效性。它可以有一个toString()方法,该方法返回对象的可读描述,等等。听起来不错。因此,我应该创建该类并将其注入每个货币对象并执行转换。但是,我应该如何处理汇率存储,或者如何正确执行汇率检测?提前和对于这些错误,我深表歉意,我仍然是新手。这要视情况而定。这是一个真正的应用程序,其中存储实际上意味着持久存储吗?如果是,请使用数据库。如果这是一个玩具项目,其中所有内容都在内存中,您可能应该使用一个映射,其中CurrencyPair包含源货币和目标货币,是不可变的,并定义适当的equals()和hashCode()方法。这将允许O(1)查阅。这并不是问题的答案。若要评论或要求作者澄清,请在其帖子下方留下评论。-@DavidMaze>我也想听听您对总体设计的看法。我非常感谢您的解释。我将尝试您建议的方法,看看这是否适合我的情况。这这不是一个真正的项目,这只是我正在做的一个个人项目。你的解决方案太棒了。我从来没有想过我可以这样做,谢谢你,先生!还有一个问题,让每种货币都有自己的汇率是一个好主意吗?把它们分开,这样我就可以更容易地更新它们,不是更好吗?不知道你从哪里开始以数据为基础,但如果您对其进行排序,则应具有多组货币。您将始终必须先找到一种货币,然后再找到另一种货币。如果您将所有货币放入一个集合,则基本上具有成对的汇率。如果这取决于您的真实世界模型。例如,一家银行可能支持某一组货币,而另一家银行可能支持另一组货币ght支持另一个。因此,您可以创建一个银行类,并在其中包含一组
货币。@k-nicholas嗯。我已成功构建了自己的解决方案,将其用作模板。我的问题是:对于Set logi
package currency;

public class Euro implements ICurrency {
    private String id;
    private IConversionRate conversionRateFinder;

    public Euro(String id, IConversionRate conversionRateBuilder) {
        this.id = id;
        this.conversionRateFinder = conversionRateBuilder;
    }

    @Override
    public double convertTo(double amount, ICurrency newCurrency) {
        double currentConversionRate  = conversionRateFinder.find(this, newCurrency);
        double newAmount = newCurrency.convert(amount,currentConversionRate);
        return newAmount;
    }

    @Override
    public double convert(double oldCurrencyAmount, double currentConversionRate) {
        return oldCurrencyAmount*currentConversionRate;
    }


    public String getId() {
        return id;
    }
}
public class Currency {
    private final String symbol; 
    private final Set<ExchangeRate> rates = new HashSet<>();

    public Currency(String symbol) {
        this.symbol = symbol;
    }
    public BigDecimal convert(Currency currency, BigDecimal amount) {
        return findExchangeRate(currency).getRate().multiply(amount).setScale(2, RoundingMode.HALF_DOWN);
    }
    public String getSymbol() {
        return symbol;
    }
    public ExchangeRate findExchangeRate(Currency currency) {
        for(ExchangeRate rate: rates) {
            if ( rate.getCurrency().equals(currency)) {
                return rate;
            }
        }
        throw new IllegalArgumentException("Currency not found: " + currency);
    }
    public void setExchangeRate(ExchangeRate rate) {
        if ( rates.contains(rate) ) rates.remove(rate);
        rates.add(rate);
    }
    public boolean removeExchangeRate(ExchangeRate rate) {
        return rates.remove(rate);
    }
public class ExchangeRate {
    private final Currency currency;
    private final BigDecimal rate;
    public ExchangeRate(Currency currency, BigDecimal rate) {
        this.currency = currency;
        this.rate = rate;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((currency == null) ? 0 : currency.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ExchangeRate other = (ExchangeRate) obj;
        if (currency == null) {
            if (other.currency != null)
                return false;
        } else if (!currency.equals(other.currency))
            return false;
        return true;
    }
Currency usd = new Currency("USD");
Currency eur = new Currency("EUR");
usd.setExchangeRate(new ExchangeRate(eur, new BigDecimal("0.87540")));
eur.setExchangeRate(new ExchangeRate(usd, new BigDecimal("1.14233")));

BigDecimal myMoney = new BigDecimal("1000.00");
myMoney = usd.convert(eur, myMoney);
System.out.println("My Euros: " + myMoney);
myMoney = eur.convert(usd, myMoney);
System.out.println("My Dollars: " + myMoney);