6

我想编写一个可以将一个单元转换为另一个单元的程序。假设我有两种方法。第一种方法可以进行公制转换,第二种方法可以进行重量转换。例如;

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结构。我的程序可以转换这些东西和对立面;

  • 海里公里
  • 海里英里
  • 英尺-公里
  • 英尺-密尔
  • 磅-公斤
  • on-gr
  • 公司 - 厘米
  • 码 - 米
  • 节-公里

我的问题:我不想使用if-elseorswitch-case结构体进行转换。(因为如果我使用 if-else 结构体,我的代码看起来很糟糕,非常简单和缓慢。如果我需要超过 50 个 if-else 结构体使用这些结构。这很糟糕。)

我可以在不使用 if-else 或 switch-case 的情况下为这些转换编写算法吗? 我的目的是更少的代码,更多的工作。关于算法的任何提示?

4

5 回答 5

13

您不需要if-then-else- 事实上,您的程序中不需要控制语句。您所需要的只是一个查找表 - 一个Map将您的单位枚举转换为double转换因子的表格,这样以单位为单位的度量乘以转换因子,您就可以得到空间单位的米和重量单位的公斤。相反,将米除以该因子会为您提供所需的单位。

有了这张地图,您可以对所有单位对进行转换:

  • 查找Cs源单位的换算系数
  • 查找Cd目标单位的换算系数
  • value * Cs / Cd作为您的结果返回。

例如,假设您要处理米、码、英寸和英尺。您的地图将如下所示:

  • 米 - 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
于 2013-07-09T12:37:56.860 回答
2

我建议引入一个类型“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));
    }
}

您可以在计算时使用原始值并创建新的指标值。您还可以为基本或复杂的算术运算添加操作。

这里省略了吸气剂。

于 2013-07-09T13:19:30.257 回答
1

在您的枚举中,您可以在枚举类型上实现 fromString 方法,假设您的枚举名称是“距离”

private static final Map<String,Distances> stringToEnum = new HashMap<String,Distances>;

初始化地图:

  static{
        for(Distances distance: values()) {
            stringToEnum.put(distance.toString(),distance);
        }
  }

返回字符串的枚举类型:

public static Distances getDistance(String stringValue){
    return stringToEnum.get(stringValue);
}

在您的方法中,您可以传入:

Distance.getDistance("feet").getCalculatedDistance()
于 2013-07-09T13:12:25.300 回答
1

将它们的相对值与枚举中的变量相关联(我猜你有一个用于距离,一个用于权重),例如enum Distances { CM(100), M(100*1000), IN(254) },... 然后你只需要获得提供的值的比率,乘以第一个参数,你就有了你的结果。如果您想要一个不错的精度,请使用以 100 或 1000 为基数的最小单位。

于 2013-07-09T12:34:24.037 回答
1

选择其中一种单位作为“基本”单位(一种用于重量,例如gr;另一种用于距离,例如m)。然后使用每个值的转换率添加方法toBaseUnit和枚举。fromBaseUnit

不涉及“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查找和遍历枚举值)之外,这种方法的主要优点是,如果您需要更复杂的转换操作(例如,Temperature带有摄氏度、华氏温度和开尔文的枚举),您可以覆盖fromBaseUnittoBaseUnit在枚举值主体。


工作示例

我使用BigDecimal进行转换比率和内部计算,以便更好地控制精度和舍入行为。

于 2013-07-09T12:44:05.893 回答