没有“if-else”或“switch-case”的度量转换算法
我想编写一个可以将一个单元转换为另一个单元的程序。 假设我有2种方法。第一种方法可以进行度量转换 ,第二种方法可以进行权重转换 。 例如;
1. long km=metricConvLength(long mil,Enum.mil,Enum.km);//first method
2. long agirlik=metricConvWeight(long kg,Enum.mil,Enum.km);//second method
我想对这些变量使用Enum结构。 我的程序可以转换这些东西和对立面;
- 海里 – 公里
- 海里英里
- 英尺 – 公里
- 英尺 – 米尔
- 磅 – 公斤
- ons- gr
- inc – cm
- 院子里 – 米
- 结 – 公里
我的问题:我不想使用if-else
或switch-case
结构来进行转换。(因为如果我使用if-else结构,我的代码看起来很糟糕,很容易和慢。如果我需要50以上-else struct,如果我使用这些struct.This is grind。)
我可以在不使用if-else或switch-case的情况下为这些转换编写算法。 我的目的是减少代码,减少工作量。 关于算法的任何提示?
你不需要if-then-else
– 事实上,你不需要程序中的控制语句。 您所需要的只是一个查找表 – 一个将您的单位枚举转换为double
转换因子的地图,这样您可以将度量单位乘以您获得的空间单位米的转换因子,以及单位重量的公斤数。 相反,按该因子划分米可以得到所需的单位。
有了这张地图,您就可以为所有单位对进行转换:
- 查找源单元的转换因子
Cs
- 查找目标单位的转换因子
Cd
- 返回
value * Cs / Cd
作为结果。
例如,假设您要处理米,码,英寸和英尺。 你的地图看起来像这样:
- m – 1.0
- y – 0.9144
- 在 – 0.0254
- 英尺 – 0.3048
现在让我们假设你要将7.5
码转换为英尺:
- 查找
Cs = 0.9144
- 查找
Cd = 0.3048
- 计算并返回
Res = 7.5 * 0.9144 / 0.3048 = 22.5
我建议引入一种类型“MetricValue”。 软件工程的历史充满了程序员忘记了他们使用的值的单位的项目。 由此产生的灾难是众所周知的。
而且,我会提出一个不可变类,因为它使许多设计方面更简单。
定义基本单位可以在您首次将所有值转换为基本单位时对您有所帮助,然后将该值转换为目标单位。 您也可以应用矩阵,但是您需要预先计算值。 矩阵的大小将为n ^ 2,而从和到基本单位的转换仅保留n个值。 如果您使用耗费资源的复杂转换公式,那么它是有道理的。 否则,关于努力的好处(太小)。
这段代码怎么样?
public class MetricValue { public static enum Unit { m(1.0d), y(0.9144d), in(0.0254d), ft(0.3048d); final static Unit baseUnit = m; final double perBaseUnit; private Unit(double inM) { this.perBaseUnit = inM; } public double fromBaseUnit(double value) { return value / perBaseUnit; } public double toBaseUnit(double value) { return value * perBaseUnit; } } final double value; final Unit unit; public MetricValue(double value, Unit unit) { super(); this.value = value; this.unit = unit; } public MetricValue to(Unit newUnit) { Unit oldUnit = this.unit; return new MetricValue(newUnit.fromBaseUnit(oldUnit.toBaseUnit(value)), newUnit); } @Override public String toString() { return value + " " + unit.name(); } public static void main(String[] args) { MetricValue distanceInM = new MetricValue(1, Unit.m); MetricValue distanceInFt = new MetricValue(6, Unit.ft); System.out.println(distanceInM); System.out.println(distanceInM.to(Unit.y)); System.out.println(distanceInM.to(Unit.y).to(Unit.m)); System.out.println(distanceInM.to(Unit.y).to(Unit.ft)); System.out.println(distanceInFt.to(Unit.m)); } }
您可以使用原始值并在计算时创建新的度量标准值。 您还可以为基本或复杂的算术运算添加操作。
这里省略了吸气剂。
将它们的相对值与你的枚举中的变量相关联(我猜你有一个用于距离,一个用于权重),例如enum Distances { CM(100), M(100*1000), IN(254) }
,…然后你只需要得到所提供值的比率,乘以第一个参数,就可以获得结果。 如果您想要一个合适的精度,请使用基础100或1000作为最小单位。
在你的枚举中你可以在枚举类型上实现一个fromString方法,让你说你的枚举名称是’距离’
private static final Map stringToEnum = new HashMap;
初始化地图:
static{ for(Distances distance: values()) { stringToEnum.put(distance.toString(),distance); } }
返回String的enumType:
public static Distances getDistance(String stringValue){ return stringToEnum.get(stringValue); }
在你的方法中你可以传入:
Distance.getDistance("feet").getCalculatedDistance()
选择其中一个单元作为“基础”单元(一个用于重量,例如gr ;一个用于距离,例如m )。 然后使用每个值的转换比率将方法添加到toBaseUnit
和toBaseUnit
到您的枚举。
不涉及“ifs”,您的转换方法将如下所示:
ResultingUnit.fromBaseUnit(originalUnit.toBaseUnit(value));
示例枚举:
public enum Distance { METER(new BigDecimal("1.0")), // Base Unit is METER KM(new BigDecimal("1E3")), CM(new BigDecimal("1E-2")); private final static MathContext MC = new MathContext(30, RoundingMode.HALF_EVEN); private final BigDecimal conversionRatio; Distance(BigDecimal conversionRatio) { this.conversionRatio = conversionRatio; } long fromBaseUnit(BigDecimal baseUnit) { return baseUnit.divide(conversionRatio, MC).longValue(); } // returns BigDecimal to avoid rounding two times // and possible division by zero BigDecimal toBaseUnit(long originalUnit) { return BigDecimal.valueOf(originalUnit).multiply(conversionRatio); } }
和改编的转换方法:
public long metricConvLength(long value, Distance orgUnit, Distance resultUnit) { return resultUnit.fromBaseUnit(orgUnit.toBaseUnit(value)); }
除了稍快一些(通过避免Map
查找和循环枚举值),这种方法的主要优点是,如果您需要更复杂的转换操作(例如,具有Celsius,Farenheit和Kelvin的Temperature
枚举),您可以覆盖fromBaseUnit
和枚举值体中的toBaseUnit
。
工作实例 。
我已经使用BigDecimal进行转换率和内部计算,以便更好地控制精度和舍入行为。