为了账号安全,请及时绑定邮箱和手机立即绑定

用于存储货币汇率的设计

用于存储货币汇率的设计

holdtom 2021-07-08 14:11:53
我开始了一个新的信用管理项目,我已经到了必须处理货币兑换的地步。(例如欧元 -> 美元)所以我进行了一些头脑风暴并得到了这个:货币是抽象的,每一种新货币都是一个接口的实现建立了一个汇率类,它存储了一个数组列表 pair<pair,double>(我在想像欧元、美元、1.14 这样的东西 -> 欧元兑美元的汇率是 1.14)并且有一些功能,比如:货币汇率存储,正确汇率的查找器(它是一个函数,它获取当前货币和新货币作为参数,并在列表中执行搜索,返回适当的货币)和一个确定货币对指数的效用函数。现在,我正在考虑性能。我相信我的设计包含一些冗余:如果我有欧元对美元,我必须有美元对欧元。此外,对于更多条目(假设为 100k),我的存储(pair<pair,double> 的数组列表)的效率如何?我有哪些替代方案?我知道有很多数据结构,但我真的不知道该选择什么。现在,对于代码:转化率等级: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);    }   
查看完整描述

2 回答

?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

我认为你应该开始更简单。我没有看到货币接口的原因,尤其是在这种情况下,因为我看不到您的实现将如何需要不同的提供者。每个Currency都由一个符号和一组该货币的汇率表示。


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);

    }

AnExchangeRate是所兑换货币的汇率,因此您无需每次都为该货币重复 1.0。不要忘记@Override hashCode,equals所以Set逻辑将正常工作。


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);

注意 的用法BigDecimal。由于浮点数和双精度数的准确性失败,这种或类似的东西对于货币计算总是必要的。您可以转换为LongorInteger并自己跟踪比例,但您将做与BigDecimal班级相同的事情。


查看完整回答
反对 回复 2021-07-14
?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

实际上,Kent Beck 在他关于 TDD 的书中就解决了这个问题。

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

我不知道,如果像创建类DollarEuro是一个不错的办法。也许只是坚持Money并保持货币在实例变量(KISS)中会更容易。我想我会想货币由一个类(完全处理BankExchangeRate或什么最适合你),我会让Money情况不变。所有计算都是按Sum类进行的(或者其他什么,重点是将逻辑从货币本身移开)。

不管怎样,也许你应该看看贝克的书。我很确定他设计得很好。


查看完整回答
反对 回复 2021-07-14
  • 2 回答
  • 0 关注
  • 192 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信