我有两个方法,一个计算被认为具有比给定对象更低值的对象的数量,另一个计算具有比给定对象更高值的对象的数量。你可以说,这两种方法实际上是相同的:
public int countHigher(SomeObject a){
if (a == null){
throw etc...
}
int numberHigher = 0;
for (SomeObeject b : this.listOfSomeObjects) {
if (b.compareTo(a) == 1) {
numberHigher++;
}
}
return numberHigher;
}
public int countLower(SomeObject a){
if (a == null){
throw etc...
}
int numberLower = 0;
for (SomeObeject b : this.listOfSomeObjects){
if (b.compareTo(a) == -1){
numberLower++;
}
}
return numberLower;
}
我重构了调用私有方法的方法:
private int coun(SomeObject a, int comparison){
if (a == null){
throw etc...
}
int number = 0;
for (SomeObeject b : this.listOfSomeObjects){
if (b.compareTo(a) == comparison){
number++;
}
}
return number;
}
但我觉得这个解决方案并不令人满意。可以使用无效的整数(即10)调用私有方法,并且对这种情况进行额外的错误检查是相当丑陋的:
if (comparison < -1 || comparison > 1)
{
throw blah
}
使用布尔值也不能令人满意,因为将来我可能想要计算相等值的对象数。
您是否有其他重构解决方案?
干杯,
皮特
答案 0 :(得分:9)
我会做什么:
int comparison
参数。这将为您提供适当的分离问题。
答案 1 :(得分:4)
我同意 - 直接与整数进行比较是脆弱的,因为比较只能保证返回,例如小于零,而不是具体-1。
您可以使用谓词来执行比较。这封装了您想要计算的条件的评估。例如,
abstract class ComparisonPredicate
{
private SomeObject a;
// set in constructor
public abstract boolean evaluate(SomeObject b);
}
class LessThanPredicate extends ComparisonPredicate
{
public boolean evaluate(SomeObject b) {
return a.compareTo(b)<0;
}
}
然后count方法变为:
private int count(ComparisonPredicate comparison){
int number = 0;
for (SomeObeject b : this.listOfSomeObjects){
if (comparison.evaluate(b)){
number++;
}
}
return number;
}
然后调用该方法:
SomeObject a = ...;
int lessThanCount = count(new LessThanPredicate(a));
这可用于查找任何类型评估的对象数量 - 不仅小于/大于比较,还包括相等以及在对象上定义的任何其他关系。
或者,您可以将比较值标准化为-1,0,1。
答案 2 :(得分:3)
使用Enums
public class test {
private int count(Object a, Comparison c){
if (a == null){
throw new RuntimeException();
}
int number = 0;
for (Object b : new Object[] {null, null}){
if (b.compareTo(a) == c.val()){
number++;
}
}
return number;
}
public void test() {
System.out.println(count(null, Comparison.GT));
System.out.println(count(null, Comparison.LT));
}
}
class Object implements Comparable {
public int compareTo(java.lang.Object object) {
return -1;
}
}
enum Comparison {
GT { int val() { return 1; } },
LT { int val() { return -1; } };
abstract int val();
}
如果你想扩展它以检查equals,你只需要在枚举中添加一个额外的值。
答案 3 :(得分:0)
论证应该是比较者(http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html) 然后,您可以使用匿名类调用该方法,以避免在一个地方只需要它时显式实现Comparator。如果方法变得更加复杂,您可能需要定义自己的接口来封装更复杂的逻辑,例如if语句本身内部的逻辑。
此外,如果要求您投票支持使用Java语言实现labmdas(闭包):)
答案 4 :(得分:0)
您可以使用enum
代替int
。此外,通常a.compareTo(b)
可以在a
小于b
时返回任意负数,在a
大于b
时返回任意正数。< / p>
这是我的解决方案:
private static enum CountMode {CountHigher, CountLower};
private int count(SomeObject anObject, CountMode mode) {
if (a == null) {
// handle
}
int count = 0;
for (SomeObject o : this.listOfSomeObjects) {
int compare = o.compareTo(anObject);
if (compare > 0 && mode == CountMode.CountHigher) {
count++;
} else if (compare < 0 && mode == CountMode.CountLower) {
count++;
}
}
return count;
}
以下是处理相同案例的修改后的代码:
private static enum CountMode {CountHigher, CountLower, CountEqual};
private int count(SomeObject anObject, CountMode mode) {
if (a == null) {
// handle
}
int count = 0;
for (SomeObject o : this.listOfSomeObjects) {
int compare = o.compareTo(anObject);
if (compare > 0 && mode == CountMode.CountHigher) {
count++;
} else if (compare < 0 && mode == CountMode.CountLower) {
count++;
} else if (compare == 0 && mode == CountMode.CountEqual) {
count++;
}
}
return count;
}
答案 5 :(得分:0)
我同意许多其他人的意见;一个Predicate
- 类型的对象在这里是正确的,但是特别想要调出mdma的观点,假设依赖于int
的{{1}}结果是不正确的(或者至少是脆弱的) - 它只是保证Comparable.compareTo()
返回正数,0或负数,特定值1和-1不是必需的(并且许多实现不会重新执行这些)。再一次,我认为Comparable
是可行的,但作为解决此问题的方法,以及人们传入Predicate
int的风险,您可能会这样做:
non-standard
使用/**
* ...
* @param int the sign of the comparison; will count objects whose .compareTo(a)
* returns an int with the same sign as this value
*/
private int count(SomeObject a, int comparisonSign){
...
for (SomeObject b : this.listOfSomeObjects){
if (Math.signum(b.compareTo(a)) == Math.signum(comparison)){
number++;
}
}
return number;
}
意味着您始终在比较-1.0,0或1.0值。
同样,我不推荐这种方法(认为它使API非常不明显,一开始),但我认为我出于好奇而把它放在这里。
答案 6 :(得分:0)
这里的大多数答案都涵盖了您的选择,但我还要再添加一个:更好的数据结构。
根据您的数据的性质,SortedSet<E>
或更丰富的NavigableSet<E>
可能会更好地满足您的目的。具体来说,这三种方法很有意义:
headSet(E toElement, boolean inclusive)
:返回此集合部分的视图,其元素小于(或等于,如果inclusive
为真)toElement
。
tailSet(E fromElement, boolean inclusive)
:返回此集合部分的视图,其元素大于(或等于,如果inclusive
为真)fromElement
。
subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
:返回此集合部分的视图,其元素范围从fromElement
到toElement
。
以下是一个示例用法(see also on ideone.com):
import java.util.*;
public class NavigableSetExample {
public static void main(String[] args) {
NavigableSet<String> names = new TreeSet<String>(
Arrays.asList(
"Bob", "Carol", "Alice", "Jill", "Jack", "Harry", "Sally"
)
);
System.out.println(names);
// [Alice, Bob, Carol, Harry, Jack, Jill, Sally]
// "Carol" and up
System.out.println(names.tailSet("Carol", true));
// [Carol, Harry, Jack, Jill, Sally]
// below "Elizabeth"
System.out.println(names.headSet("Elizabeth", false));
// [Alice, Bob, Carol]
// who stands between "Harry" and "Sally"?
System.out.println(names.subSet("Harry", false, "Sally", false));
// [Jack, Jill]
}
}
如果地图比集合更适合,那么当然有NavigableMap<K,V>
。
SortedSet/Map
与NavigableSet/Map
答案 7 :(得分:-1)
我建议包装一个私有方法并使用函数对象模式:
功能对象的接口:
interface Filter<T>{
boolean eligible(T t);
}
计算更高的包装器方法以显示这个想法:
public int countHigher(final SomeObject a)
{
return coun(a, new Filter<SomeObject>()
{
public boolean eligible(SomeObject b){
return a.compareTo(b) == -1;
}
});
}
计算符合条件的对象的私人帮助方法
private int coun(SomeObject a, Filter<SomeObject> filter){
//...
}