问题背景,定义三个概念先:
1。percent。就是百分比。
2。weight。如果percent是10,weight就是0.1,weight=percent/100.
3。amount。如果percent是10,总数是1000,那么amount就是100. amount=total*weight.
在程序中,我们很多时候需要在amount, weight, percent之间来回转换。根据不同模块的需要,把同一个数据点转换成percent或者weight或者amount。
目标是设计一个类Portion,它的接口如下:
[code]
public class Portion {
public double getPercent();
public double getWeight();
public double getAmount();
public double getTotal();
public static Portion fromPercent(double total, double percent);
public static Portion fromWeight(double total, double weight);
public static Portion fromAmount(double total, double amount);
}
[/code]
另外,程序中还使用这样一个习惯:如果total为0,那么从amount计算percent和weight的时候也是0。(以避免divide by 0)
我的pair想这样实现:
[code]
public class Portion {
private final double total;
private final double amount;
Portion(double total, double amount) {
this.total = total;
this.amount = amount;
}
public double getPercent() {
return getWeight()*100;
}
public double getWeight() {
return total==0?0:amount/total;
}
public double getAmount() {
return amount;
}
public double getTotal() {
return total;
}
public static Portion fromPercent(double total, double percent) {
return new Portion(total, total*percent/100);
}
public static Portion fromWeight(double total, double weight) {
return new Portion(total, total*weight);
}
public static Portion fromAmount(double total, double amount) {
return new Portion(total, amount);
}
}
[/code]
我对这个设计是不满意的。我提出了几点问题:
1。假设在某一点total不可知,那么怎样用Portion来封装唯一可知的percent/weight?Portion.fromWeight(0, 0.1).getPercent()在这个设计中不会返回我期待的10,而是0。
2。double是有误差的。如果客户写一个
[code]
assertEquals(weight, Portion.fromWeight(777, weight).getWeight(), 0)[/code]
居然也要失败,不免尴尬。
所以我提议这样做:
[code]
public class Portion {
private final double total;
private final double amount;
private final double percent;
private final double weight;
Portion(double total, double amount, double percent, double weight) {
this.total = total;
this.amount = amount;
this.percent = percent;
this.weight = weight;
}
public double getPercent() {
return percent;
}
public double getWeight() {
return weight;
}
public double getAmount() {
return amount;
}
public double getTotal() {
return total;
}
public static Portion fromPercent(double total, double percent) {
return new Portion(total, total*percent/100, percent, percent/100);
}
public static Portion fromWeight(double total, double weight) {
return new Portion(total, total*weight, weight*100, weight);
}
public static Portion fromAmount(double total, double amount) {
double weight = total==0?0:amount/total;
return new Portion(total, amount, weight*100, weight);
}
}
[/code]
这样,虽然double计算有误差,我至少可以保证Portion.fromWeight(total, weight).getWeight()永远等于weight。
但是,pair对这种设计感觉不舒服,他不喜欢把逻辑放在静态工厂方法中。
而且,pair对我提出的几个他的方案的缺陷如此回应:
1。total为0的情况本身就特殊。根据整个系统目前的情况,getWeight()和getPercent()都返回0可以接受。
2。我不care是否有误差,反正我们现在比较double的时候都是用一个tolerance的。
我的pair对整个系统了解的比我多,我相信他说的话。只不过,要我做一个单独的小模块,却总要依赖于外部系统的“对特殊情况A,我们可以容忍;对情况B,我们不在乎”这些assumption,让我深藏于心底的洁癖非常不舒服。
我并不是绝对排斥使用适当的assumption来简化实现复杂度。但是当两个方案的复杂度相近时,我很反感把外界的一些assumption引进来。
那么,你怎么想?
1。percent。就是百分比。
2。weight。如果percent是10,weight就是0.1,weight=percent/100.
3。amount。如果percent是10,总数是1000,那么amount就是100. amount=total*weight.
在程序中,我们很多时候需要在amount, weight, percent之间来回转换。根据不同模块的需要,把同一个数据点转换成percent或者weight或者amount。
目标是设计一个类Portion,它的接口如下:
[code]
public class Portion {
public double getPercent();
public double getWeight();
public double getAmount();
public double getTotal();
public static Portion fromPercent(double total, double percent);
public static Portion fromWeight(double total, double weight);
public static Portion fromAmount(double total, double amount);
}
[/code]
另外,程序中还使用这样一个习惯:如果total为0,那么从amount计算percent和weight的时候也是0。(以避免divide by 0)
我的pair想这样实现:
[code]
public class Portion {
private final double total;
private final double amount;
Portion(double total, double amount) {
this.total = total;
this.amount = amount;
}
public double getPercent() {
return getWeight()*100;
}
public double getWeight() {
return total==0?0:amount/total;
}
public double getAmount() {
return amount;
}
public double getTotal() {
return total;
}
public static Portion fromPercent(double total, double percent) {
return new Portion(total, total*percent/100);
}
public static Portion fromWeight(double total, double weight) {
return new Portion(total, total*weight);
}
public static Portion fromAmount(double total, double amount) {
return new Portion(total, amount);
}
}
[/code]
我对这个设计是不满意的。我提出了几点问题:
1。假设在某一点total不可知,那么怎样用Portion来封装唯一可知的percent/weight?Portion.fromWeight(0, 0.1).getPercent()在这个设计中不会返回我期待的10,而是0。
2。double是有误差的。如果客户写一个
[code]
assertEquals(weight, Portion.fromWeight(777, weight).getWeight(), 0)[/code]
居然也要失败,不免尴尬。
所以我提议这样做:
[code]
public class Portion {
private final double total;
private final double amount;
private final double percent;
private final double weight;
Portion(double total, double amount, double percent, double weight) {
this.total = total;
this.amount = amount;
this.percent = percent;
this.weight = weight;
}
public double getPercent() {
return percent;
}
public double getWeight() {
return weight;
}
public double getAmount() {
return amount;
}
public double getTotal() {
return total;
}
public static Portion fromPercent(double total, double percent) {
return new Portion(total, total*percent/100, percent, percent/100);
}
public static Portion fromWeight(double total, double weight) {
return new Portion(total, total*weight, weight*100, weight);
}
public static Portion fromAmount(double total, double amount) {
double weight = total==0?0:amount/total;
return new Portion(total, amount, weight*100, weight);
}
}
[/code]
这样,虽然double计算有误差,我至少可以保证Portion.fromWeight(total, weight).getWeight()永远等于weight。
但是,pair对这种设计感觉不舒服,他不喜欢把逻辑放在静态工厂方法中。
而且,pair对我提出的几个他的方案的缺陷如此回应:
1。total为0的情况本身就特殊。根据整个系统目前的情况,getWeight()和getPercent()都返回0可以接受。
2。我不care是否有误差,反正我们现在比较double的时候都是用一个tolerance的。
我的pair对整个系统了解的比我多,我相信他说的话。只不过,要我做一个单独的小模块,却总要依赖于外部系统的“对特殊情况A,我们可以容忍;对情况B,我们不在乎”这些assumption,让我深藏于心底的洁癖非常不舒服。
我并不是绝对排斥使用适当的assumption来简化实现复杂度。但是当两个方案的复杂度相近时,我很反感把外界的一些assumption引进来。
那么,你怎么想?