我已经开始了一个信贷管理的新项目,现在我不得不处理货币兑换。 (例如,欧元->美元)因此,我做了一些头脑风暴,并得到了以下信息:

货币是抽象的,每种新货币都是接口的实现

建立了一个汇率类别,该汇率类别存储对(pair,pair,double)的数组列表(我想到的是欧元,美元,1.14->欧元对美元的汇率是1.14)并具有以下功能:货币汇率存储,一个用于正确汇率的查找器(该函数将当前货币和新货币作为参数,并在列表中进行搜索,然后返回适当的货币)和一个实用函数,该函数确定货币对的索引。

现在,我正在考虑性能。我相信我的设计包含一些冗余:如果我有欧元兑美元,我就必须有美元兑欧元。此外,对于大量条目(假设100k),我的存储(pair 的数组列表)的效率如何?我有什么选择?

我知道有很多数据结构,我真的不知道该选什么。

现在,对于代码:

转化率等级:

package currency;

import javafx.util.Pair;

import loggers.ILogger;

import java.util.ArrayList;

public class ConversionRates implements IConversionRate {

private ArrayList, Double>> conversionRates;

private ILogger log;

public ConversionRates(ArrayList, 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, Double> selectedPair = conversionRates.get(index);

double rate = selectedPair.getValue();

return rate;

}

private int searchPairs(String first, String second) {

Pair 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, Double> newRate) {

log.add("Added new rate" + newRate);

conversionRates.add(newRate);

}

@Override

public void update(ArrayList, Double>> newRates) {

log.add("Updated rates");

conversionRates.clear();

conversionRates.addAll(newRates);

}

@Override

public void remove(Pair, Double> redundantRate) {

log.add("Removed rate" + redundantRate);

conversionRates.remove(redundantRate);

}

}

ConversionRates接口:

package currency;

import javafx.util.Pair;

import java.util.ArrayList;

public interface IConversionRate {

double find(ICurrency euro, ICurrency newCurrency);

void add(Pair,Double> newRate);

void update(ArrayList< Pair,Double> > newRates);

void remove(Pair,Double> redundantRate);

}

货币界面:

package currency;

public interface ICurrency {

double convertTo(double amount, ICurrency newCurrency);

double convert(double oldCurrencyAmount, double conversionRateToNewCurrency);

String getId();

}

货币实现(由于欧元完全相同,因此我仅列出欧元):

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;

}

}

我也想听听您的一般设计。

在关心性能之前,您应该关心可读性。我不知道ArrayList ,Double >>可能包含什么。定义类,枚举,它们的名称应清楚地表明它们所代表的含义。请注意,Java和Guava均不包含Pair类,这恰恰是因为它鼓励开发人员编写不可读的代码,例如您所拥有的代码。

第一对代表货币,双倍代表从第一对第二货币的实际汇率。

然后,定义并使用具有三个字段的CurrencyConversion类:Currency sourceCurrency,Currency targetCurrency,double conversionRate。其方式更具可读性。它可以包含实际计算转化的方法。它可以包含简单地通过交换两种货币并反转汇率来创建反向CurrencyConversion的方法。它可以在施工时验证费率的有效性。它可以具有toString()方法,该方法返回对象的可读描述等。

听起来不错。因此,我应该创建该类并将其注入每个货币对象并执行转换。但是,我应该如何处理汇率的存储,或者应该如何正确执行汇率汇率的检测?提前坦克,我为这些错误表示歉意,我仍然是菜鸟。

这取决于。这是一个真正的应用程序,存储实际上意味着持久存储吗?如果是这样,请使用数据库。如果它是一个玩具项目,其中的所有内容都在内存中,则您可能应该使用Map (其中CurrencyPair包含源货币和目标货币)是不可变的,并定义适当的equals()和hashCode()方法。这将允许O(1)查找。

这不是一个真正的应用程序,但我要考虑到这一点。我将使用序列化。

也许Joda-Money项目可能会有所帮助?

我认为您应该更简单一些。我看不到使用货币接口的原因,特别是在这种情况下,因为我看不到您的实现将如何需要不同的提供程序。每个Currency用一个符号和该货币的一组汇率表示。

public class Currency {

private final String symbol;

private final Set 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);

}

ExchangeRate是所交换货币的汇率,因此您无需每次都重复该货币的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的用法。由于浮点数和双精度数的准确性失败,因此对于货币计算始终必须使用这种或类似的方法。您可以转换为Long或Integer并自己跟踪缩放,但您将执行与BigDecimal类相同的操作。

您的解决方案很棒。我从来没有想过我可以那样做,谢谢您,先生!

还有一个问题,让每种货币拥有自己的汇率是一个好主意吗?将它们分开以便更好地更新它们会更好吗?

不确定数据的开头是什么,但是如果对数据进行排序,您应该具有货币组。您将永远必须先找到一种货币,然后再找到另一种。如果将所有货币都放入一个集合中,那么基本上就是一对汇率。是否取决于您的实际模型。例如,一家银行可能支持某种货币,而另一家银行可能支持另一种货币。因此,您可以进行银行分类并在其中添加Set货币。

@ k-nicholas嗯。我已经成功地构建了自己的解决方案,并以此为模板。我的问题是:为了使设置逻辑起作用,除了覆盖"等于"和" hashCode"方法之外,我还需要做其他事情吗?假设我要执行搜索,是否必须调用" hashCode()"? (PS:直到这个项目,我还没有碰过集和散列)

新问题应该是新职位。 stackoverflow.com/questions/5396939/

实际上,肯特·贝克(Kent Beck)在其有关TDD的书中就致力于解决此问题。

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

我不确定创建类似Dollar和Euro的类是否是一个好方法。也许坚持使用Money并将货币保留在实例变量(KISS)中可能会更加容易。我想我希望一种类别(Bank,ExchangeRate或最适合您的任何一种)完全处理货币,并使Money实例不可变。而且所有的计算都是由Sum类进行的(或其他任何方法,关键是要使逻辑远离金钱本身)。

无论如何,也许您应该只看一下贝克的书。我敢肯定他的设计很好。

这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方发表评论。 -来自评论

@DavidMaze>我也想听听您的一般设计。

我非常感谢您的解释。我将尝试您建议的方法,并看如何适合我的情况。这不是一个真正的项目,它只是我正在从事的个人项目。

java人民币换欧元_关于java:用于存储货币汇率的设计相关推荐

  1. java人民币换欧元_java – PdfBox编码符号货币欧元

    不幸的是,PDFBox的字符串编码远非完美(版本1.8.x).不幸的是,它在编码通用PDF对象中的字符串时使用相同的例程,就像在内容流中编码字符串时一样,这是根本错误的.因此,您必须自己转换为正确的编 ...

  2. java一键换壁纸_【Java】Java批量下载必应壁纸工具

    [Java] 纯文本查看 复制代码package com.ren; import java.io.BufferedOutputStream; import java.io.File; import j ...

  3. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  4. java是什么格式_是java格式

    错误:编码GBK的不可映射字符的解决办法 最近在重新补javaSE的基础,编辑器编写完代码以后,在控制台运行代码段的时候,出现了以下的错误提示:错误:编码GBK的不可映射字符 在通过查询谷哥和度娘以后 ...

  5. java语言程序设计答案_《java语言程序设计》练习题及答案

    <java语言程序设计>练习题及答案 JAVA 语言程序设计题及部分答案 一.单选题:(每题1分)下列各题A).B).C).D)四个选项中, 只有一个选项是正确的,请将正确选项的标记写在题 ...

  6. java ee开发环境_设置Java EE 6开发环境

    java ee开发环境 本教程简要说明了如何设置典型的环境来开发基于Java EE 6的应用程序. 除了可以正常工作的Windows XP客户端具有足够的CPU能力和内存外,本教程没有其他先决条件. ...

  7. java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable

    线程 1 线程概述 1.1 什么是线程 v  线程是程序执行的一条路径, 一个进程中可以包含多条线程 v  一个应用程序可以理解成就是一个进程 v  多线程并发执行可以提高程序的效率, 可以同时完成多 ...

  8. java编程基础码_【Java编程的逻辑】编程基础

    数据类型和变量 数据类型用于对数据归类,以便于理解和操做. - 整数类型:byte/short/int/long, 分别有不一样的取值范围 - 小数类型:float/double,有不一样的取值范围和 ...

  9. JAVA redis缓存过期_失效java服务器

    Java 并发/多线程教程--4并发模型 本系列译自jakob jenkov的Java并发多线程教程(本章节部分内容参考http://ifeve.com/并发编程模型),个人觉得很有收获.由于个人水平 ...

最新文章

  1. java swing中英文支持,java - Swing国际化 - 如何在运行时更新语言 - SO中文参考 - www.soinside.com...
  2. CRUX下实现进程隐藏(3)
  3. Python装饰器-装饰流程,执行顺序
  4. 第二次作业 郭昭杰 201731062608
  5. base64的php文件上传,PHP传统文件上传和Base64位文件上传
  6. 2011年全国大学生程序设计邀请赛(福州)
  7. 光纤收发器和光电转换器有什么区别?
  8. 错误记录--更改tomcat端口号方法,Several ports (8005, 8080, 8009)
  9. 输出国际象棋输出余弦曲线
  10. mybatis中resultType取出数据顺序不一致解决方法
  11. BRD、MRD 和 PRD 之间的区别与联系有哪些?
  12. 从零学javascript_我刚刚问了23,000个开发人员他们对JavaScript的看法。 这是我学到的。...
  13. iPhone 13系列或将涨价?业内人士:可能性不大,原因有这几点
  14. 北京豪宅市场调查:多项目集中放量使选择面加大
  15. HDU3032_NimOrNotNim解题报告
  16. “Kindle App中文字体9MB下载失败”解决办法
  17. 计算机ps计划,ps教学计划
  18. 异常解决 java.lang.UnsupportedOperationException: Required method destroyItem was not overridden
  19. ADC转换速率kSPS定义
  20. springboot no tests were found

热门文章

  1. 总结一个老网站数据搬家注意事项
  2. android toast居中显示_android Toast 弹出在屏幕中间位置以及自定义Toast
  3. 用余弦定理求三角形内角
  4. tsm2812通用定时器中断_基于TMS320F2812的双通道高精度伺服系统
  5. python制作文字识别_用Python轻松进行图像文本识别
  6. 极光推送服务器端文档,Android SDK 集成指南
  7. 根据系统日期,判断输出该月份所属的季节(春、夏、秋、冬)
  8. java某公司运维管理系统
  9. 网络共享 指定的服务器无法运行请求的操作,局域网共享访问故障及解决方案...
  10. 浅谈分布式一致性算法raft