[英]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.