我正在寻找一些好的模式,有可能在不同的单位表达距离。我找到了Martin Fowler article about quantities,我编写了类似的东西:
这是距离类(我认为抽象它不是必要的):
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"对于米。如果我有很多单位,我会考虑课程的数量......根据单位名称,有工厂返回米的因素是否是个好主意?单位不会有课程吗?
答案 0 :(得分:2)
嗯,我会使用enum而不是DistanceUnit类,因为它们没有不同的实例。 您可以将值设置为枚举like here
然后调用enum.getValue()而不是unit.getMetresFactor()。 它也有点令人困惑,是以米为单位的mValue值还是在DistanceUnit中,如果以米为单位,你必须有
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}
答案 1 :(得分:1)
您可以将其模拟为java.util.concurrent.TimeUnit
作为枚举。 E.g。
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
答案 2 :(得分:0)
我认为你应该使用&#34;策略&#34;图案。
界面:
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));
}
如果我理解你,我认为这是一个简单而干净的解决方案。
您可以按照此模型进行其他单位之间的转换。
答案 3 :(得分:0)
Java约定不使用m(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);