for循環求和


http://www.iteye.com/topic/39694?page=1
class Details {   
  double getBalance();   
  double getFixed();   
  double getVariable();   
  double getSpendDown();   
  ...   
  //  getter            
}  

class Details {
  double getBalance();
  double getFixed();
  double getVariable();
  double getSpendDown();
  ...
  //  getter         
}
今の業務ロジックはいくつかのpropertyに対して要求と操作をして、overallBalance、overall Fixedなどを求めます。
たいしたことないです。一つのfor循環分で解決します。
Java   
static double getOverallBalance(Details[] arr){   
  double sum = 0;   
  for(int i=0; i<arr.length; i++) {   
    sum += arr[i].getBalance();   
  }   
}  

static double getOverallBalance(Details[] arr){
  double sum = 0;
  for(int i=0; i<arr.length; i++) {
    sum += arr[i].getBalance();
  }
}
同じ理屈で、overall Fixedに対して、コードは大同小異で、copy-pasteは先に。
Java   
static double getOverallFixed(Details[] arr){   
  double sum = 0;   
  for(int i=0; i<arr.length; i++) {   
    sum += arr[i].getFixed();   
  }   
}  

static double getOverallFixed(Details[] arr){
  double sum = 0;
  for(int i=0; i<arr.length; i++) {
    sum += arr[i].getFixed();
  }
}
これは全部大丈夫です。しかし、7番目のget OverallBlah関数について書いたら、やっと我慢できなくなりました。このコードは重複しています。多くはないですが、こんなに長く支えられません。
code-against-interfaceの推賞者として、関数式プログラミングの扇子として、最も自然な考え方は異なるgetter論理を一つのGetterインターフェースに抽象化することです。
Java   
interface Getter {   
  double get(Details details);   
}   
static double sum(Details[] arr, Getter getter){   
  double sum = 0;   
  for(int i=0; i<arr.length; i++) {   
    sum += getter.get(arr[i]);   
  }   
}  

interface Getter {
  double get(Details details);
}
static double sum(Details[] arr, Getter getter){
  double sum = 0;
  for(int i=0; i<arr.length; i++) {
    sum += getter.get(arr[i]);
  }
}
ナ爱思さん。このコードよりもっと優雅なのがありますか?
各合計のコードは、次のようになります。
Java   
double overallBalance = sum(details, new Getter(){   
  public double get(Details details){   
    return details.getBalance();   
  }   
});   
double overallFixed = sum(details, new Getter(){   
  public double get(Details details){   
    return details.getFixed();   
  }   
});   
....  

double overallBalance = sum(details, new Getter(){
  public double get(Details details){
    return details.getBalance();
  }
});
double overallFixed = sum(details, new Getter(){
  public double get(Details details){
    return details.getFixed();
  }
});
....
うん。繰り返されるロジックはほとんどないです。
でも……
コードの行数を数えて、どのように減らしていないで、かえって多少利益がありますか?よく探してみます。元のfor loopが4行だったことに気づきました。今のnew Getter(){…}も4行です!!
sum()関数を加えて、長い間苦労しました。コードの行数が増えました。
もし世界にjavaの匿名の文法よりもっと臭いものがあるなら、それはたぶん匿名の文法です。java 7がclosure文法を導入する意味を疑問視する人がいるということですか?
もう一つの方法はapache commons beanutilsのget Propertyで、最終的な文法会は以下の通りです。
Java   
double overallBalance = sum(details, "balance");  

double overallBalance = sum(details, "balance");
文法は十分に簡単ですが、再構成する時は面倒です。code-copletionも利用できません。
気まずいですね。このような簡単なfor loopは匿名クラスで再構成するには値しないようです。でも就任はこの7つの顔がそっくりなfor loopでここに立っています。
途方に暮れて、奇術を練り始めた。
まず一つのインターフェースを宣言して、sumを必要とするすべてのproperty getterを含みます。
Java   
private interface IDetails {   
  double getBalance();   
  double getFixed();   
  double getVariable();   
  double getSpendDown();   
  ...   
  //       sum getter   
}  

private interface IDetails {
  double getBalance();
  double getFixed();
  double getVariable();
  double getSpendDown();
  ...
  //       sum getter
}
そしてDetailsにIDetailsを実現させます。Detailsのコードは変わりません。
Java   
class Details implements IDetails {   
  ...   
  //       
}  

class Details implements IDetails {
  ...
  //    
}
芝居の肉が来た。dynamic proxyを書いてsumロジックをカプセル化します。
Java   
static IDetails sumOf(final IDetails[] arr){   
  return (IDetails)Proxy.newProxyInstance(   
    getClass().getClassLoader(), new Class[]{IDetails.class}, new InvocationHandler(){   
    public Object invoke(Object proxy, Method method, Object[] args)   
    throws Throwable {   
      double sum = 0;   
      for(int i=0; i<arr.length; i++) {   
        sum += ((Double)method.invoke(arr[i], args)).doubleValue();   
      }   
      return new Double(sum);   
    }   
  });   
}  

static IDetails sumOf(final IDetails[] arr){
  return (IDetails)Proxy.newProxyInstance(
    getClass().getClassLoader(), new Class[]{IDetails.class}, new InvocationHandler(){
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
      double sum = 0;
      for(int i=0; i<arr.length; i++) {
        sum += ((Double)method.invoke(arr[i], args)).doubleValue();
      }
      return new Double(sum);
    }
  });
}
はい、次にsumの文法を求めて、以下のように簡略化されます。
Java   
double overallBalance = sumOf(arr).getBalance();   
double overallFixed = sumOf(arr).getFixed();   
...  

double overallBalance = sumOf(arr).getBalance();
double overallFixed = sumOf(arr).getFixed();
...
また、sumの新しいpropertyが必要です。このgetterをIDetailsインターフェースに入れるだけで成功しました。