繁体   English   中英

用不同的单位实现距离是个好方法吗

[英]Is it a good way to implement Distance with diffrent units

我一直在寻找一些好的模式来表达不同单位的距离。 我找到了有关数量的Martin Fowler文章,并编写了如下内容:

这是Distance类(我认为不必抽象):

public class Distance {
    double mValue;
    DistanceUnit mUnit;

    public Distance(double value, DistanceUnit unit){
        this.mValue = value;
        this.mUnit = unit;
    }

    public Distance toUnit(DistanceUnit unit){
        double factor = this.mUnit.getMetresFactor()/unit.getMetresFactor();
        double newValue = this.mValue * factor;
        Distance distance = new Distance(newValue, unit);
        return distance;
    }

    @Override
    public String toString(){
        return String.valueOf(mValue);
    }
}

看起来很简单。 转换为toUnit是基于DistanceUnit方法getMetresFactor 每个Unit类都实现DistanceUnit接口,并具有以下方法getMetresFactor()

public interface DistanceUnit {
    double getMetresFactor();
}


public class Inch implements DistanceUnit {
    @Override
    public double getMetresFactor() {
        return 0.0254;
    }
}


public class Kilometer implements DistanceUnit {
    @Override
    public double getMetresFactor() {
        return 1000.0;
    }
}

用法例如:

Distance inches = new Distance(300.0, new Inch());
Distance kilometres = inches.toUnit(new Kilometres());

因此它返回正确的值。

以这种方式存储距离的好方法吗? 也许您知道这种方法的一些缺点。 也许在这里使用FactoryMethod模式来构造基于基于米的单位快捷方式(例如“ m”)的距离的好主意。 如果我有很多单位,我会考虑课程的数量...让工厂根据单位名称返回米的返回因子是个好主意吗? 那会有没有班级呢?

嗯,我将使用枚举而不是DistanceUnit类,因为它们没有不同的实例。 您可以像下面这样设置枚举值

然后调用enum.getValue()而不是unit.getMetresFactor()。 还有一点让人困惑,是以m为单位的mValue值还是以DistanceUnit的形式,如果以m为单位,则必须

double factor =  unit.getMetresFactor();

好的,现在支持任何转换功能:

import java.util.HashMap;
import java.util.Map;


public abstract class MeasureConverter {

public abstract double valueToBasic(double value);

public abstract double basictoValue(double basic);

/**
 *
 */
public static Map<String, MeasureConverter> converters;

public static Map<String, MeasureConverter> getConverters() {
    if (converters == null) {
        converters = new HashMap<String, MeasureConverter>();

        converters.put("kilo", new MeasureConverter() {

            @Override
            public double valueToBasic(double value) {
                return value * 1000;
            }

            @Override
            public double basictoValue(double basic) {
                return basic / 0.001;
            }
        });

        // taking the basic temperature value in kelvines
        converters.put("kelvine", new MeasureConverter() {

            @Override
            public double valueToBasic(double value) {
                return value;
            }

            @Override
            public double basictoValue(double basic) {
                return basic;
            }
        });

        converters.put("celsius", new MeasureConverter() {

            @Override
            public double valueToBasic(double value) {
                return value + 273.15;
            }

            @Override
            public double basictoValue(double basic) {
                return basic - 273.15;
            }
        });

        converters.put("faren", new MeasureConverter() {

            @Override
            public double valueToBasic(double value) {
                return value * 1.8 - 459.67 ; // or whatever is there?
            }

            @Override
            public double basictoValue(double basic) {
                return (basic + 459.67  ) / 1.8;// or whatever is there?
            }
        });

    }

    return converters;
}

}

接着 :

import java.util.Objects;


public class MeasurePattern {

double value;
String name;

public MeasurePattern(double value, String name) {
    this.value = value;
    this.name = name;
}

@Override
public String toString() {
    return "MeasurePattern{" + "value=" + value + ", name=" + name + '}';
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 29 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
    hash = 29 * hash + Objects.hashCode(this.name);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final MeasurePattern other = (MeasurePattern) obj;
    if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) {
        return false;
    }
    if (!Objects.equals(this.name, other.name)) {
        return false;
    }
    return true;
}

public MeasurePattern convertTo(String converter) {

    MeasureConverter mycon = MeasureConverter.getConverters().get(name);
    MeasureConverter hiscon = MeasureConverter.getConverters().get(converter);

    double basic = mycon.valueToBasic(value);
    double hisValue = hiscon.basictoValue(basic);
    return new MeasurePattern(hisValue, converter);

}

public static void main(String[] args) {
    //trying temperatures;

    MeasurePattern temp = new MeasurePattern(10, "celsius");

    MeasurePattern kelvine = temp.convertTo("kelvine");
    MeasurePattern faren = kelvine.convertTo("faren");
    MeasurePattern cels = faren.convertTo("celsius");

    System.out.println("kelvine = " + kelvine);
    System.out.println("faren = " + faren);
    System.out.println("cels = " + cels);

}

}

输出:

kelvine = MeasurePattern{value=283.15, name=kelvine}
faren = MeasurePattern{value=412.67777777777775, name=faren}
cels = MeasurePattern{value=9.999999999999943, name=celsius}

您可以将它模拟实现为java.util.concurrent.TimeUnit作为枚举。 例如

public enum DistanceUnit {

  KILOMETER {
    @Override
    protected double conversionFactor(DistanceUnit toDistanceUnit) {
      switch (toDistanceUnit) {
        case KILOMETER:
          return 1;
        case MILE:
          return 0.621371;
        default:
          throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
      }
    }
  },

  MILE {
    @Override
    protected double conversionFactor(DistanceUnit toDistanceUnit) {
      switch (toDistanceUnit) {
        case KILOMETER:
          return 1.60934;
        case MILE:
          return 1;
        default:
          throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
      }
    }
  };

  public double toDistance(double value, DistanceUnit targetDistance) {
    return value * conversionFactor(targetDistance);
  }

  protected abstract double conversionFactor(DistanceUnit toDistanceUnit);

}

将您的Distance等级更改为

public class Distance {
    double mValue;
    DistanceUnit mUnit;

    public Distance(double value, DistanceUnit unit){
        this.mValue = value;
        this.mUnit = unit;
    }

    public Distance toUnit(DistanceUnit unit){
        double newValue = mUnit.toDistance(mValue, unit);
        Distance distance = new Distance(newValue, unit);
        return distance;
    }

    @Override
    public String toString(){
        return String.valueOf(mValue);
        }
}

并且客户端代码看起来非常清晰

public class Main {

  public static void main(String[] args) {
    Distance kilometers = new Distance(265.35, DistanceUnit.KILOMETER);
    Distance miles = kilometers.toUnit(DistanceUnit.MILE);
    System.out.println(miles);
  }
}

将输出

164.88079485000003

我认为您应该使用“策略”模式。

接口:

 public interface DistanceUnit {
     double getDistance(int metres);
 }

英寸类:

public class Inch implements DistanceUnit {
    @Override
    public double getDistance(int metres) {
       return meters*39; //do conversion here
    }
}

公里类:

public class Kilometres implements DistanceUnit {
    @Override
    public double getDistance(int metres) {
        return meters/1000; //do conversion here
    }
}

然后:

List<DistanceUnit> distanceList = new ArrayList<>();
distanceList.add(new Inch());
distanceList.add(new Kilometres());


for (DistanceUnit item : distanceList) {
    System.out.println(item.getDistance(1000));
}

如果我了解您,我认为这是一个简单而干净的解决方案。

您可以遵循此模型在其他单位之间进行转换。

Java约定不使用am(ember)前缀(但是说this.限定),并且约定在Java中非常重视(例如与C ++相对)。

toString错过了单位。

JScience提供了更多以不同单位m/s²进行计算的功能。 您的课程是一个很好的抽象。 但在更广泛的范围内,您可能希望进行数学运算,单位幂(上面的s为-2)。

首先看看您自己的用法想法:

(只是垃圾:)

U speedUnit = U.of(Distance::km, Time::h.up(-1));
double timeInS = U.mile(40).div(speedunit(30)).in(U.m);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM