java類中 多個方法求和.
這裡講述的是一個非常讓人尷尬的故事
我們有一個簡單的java類:
- class Details {
- double getBalance();
- double getFixed();
- double getVariable();
- double getSpendDown();
- ...
- //各種getter以及其他相關的邏輯
- }
class Details {
double getBalance();
double getFixed();
double getVariable();
double getSpendDown();
...
//各種getter以及其他相關的邏輯
}
現在業務邏輯需要對一些property做求和操作,求overallBalance, overallFixed之類的。
沒什麼了不起的,一個for迴圈分分鐘搞定:
- 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();
}
}
同理,對overallFixed,程式碼大同小異,copy-paste先。
- 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();
}
}
這都沒什麼。可是當我寫到第七個getOverallBlahBlah(arr)函式的時候,終於有點受不了了。這程式碼重複的雖然不多,但是架不住這麼沒完沒了阿。
作為code-against-interface的推崇者,作為一個函數語言程式設計的扇子,最自然的想法就是把不同的getter邏輯抽象成一個Getter介面,如下:
- 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]);
}
}
娜愛思啊。有比這程式碼更優雅的麼?
然後各個求和的程式碼變成:
- 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是四行,現在的new Getter(){...}居然也是四行!!!
再加上一個sum()函式,我辛苦了半天的重構,居然程式碼行數增加了!
如果世界上有比一個java的匿名類的語法更臭的,那大概就是兩個匿名類語法了。據說居然還有人質疑java 7引入closure語法的意義?
另一個方法是用apache commons beanutils的getProperty(),最終的語法會是:
- double overallBalance = sum(details, "balance");
double overallBalance = sum(details, "balance");
語法足夠簡單了,但是重構的時候就麻煩了,也沒有code-completion可用。
尷尬阿。這麼一個簡單的for loop,用匿名類重構似乎不值得。但是就任由這七個(也許回頭還會更多)長得一模一樣的for loop這麼站在這氣我?
走投無路,開始琢磨奇技淫巧了。
先宣告一個介面,來包含所有需要sum的property getter。
- 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的程式碼不用變。
- class Details implements IDetails {
- ...
- //程式碼不變
- }
class Details implements IDetails {
...
//程式碼不變
}
戲肉來了。寫一個dynamic proxy,來封裝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);
- }
- });
- }
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的語法可以被簡化為如下:
- double overallBalance = sumOf(arr).getBalance();
- double overallFixed = sumOf(arr).getFixed();
- ...
double overallBalance = sumOf(arr).getBalance();
double overallFixed = sumOf(arr).getFixed();
...
而且,再需要sum新的property,只需要把這個getter放進IDetails介面,就大功告成了。
很有趣的dynamic proxy應用。不過,一個求和這麼簡單的事情居然要動用這種奇技淫巧,很值得自豪麼?
要是在ruby裡,我就直接:
- sum(arr){balance}
sum(arr){balance}
該死的java啊!
相關文章
- Excel求和只有sum求和?多種高階求和方法都在這裡了!Excel
- [轉載] Java中如何在方法中return返回多個值Java
- JAVA中object類中toString()方法JavaObject
- Java Object類的各個方法JavaObject
- Java中Object類的常用方法JavaObject
- Java中Scanner類的常用方法Java
- Java中Integer類的基本方法Java
- Java中的類繼承與多型Java繼承多型
- 【Java小疑問】java原始檔當中可以有多個類,但是為什麼只能有一個public類呢?Java
- Java中String類的常用方法Java
- java中多型的理解——父類引用指向子類物件Java多型物件
- java中介面多個實現類,如何指定實現類,根據子類型別選擇實現方法Java型別
- Java中StringBuffer類的常用方法Java
- java中final類 跟final方法Java
- Java反射機制demo(五)—獲得並呼叫一個類中的方法Java反射
- 一個例項中,多個synchronized方法的呼叫synchronized
- JAVA中StringBuffer類常用方法詳解Java
- Java類方法(定義一個工具類,儲存一些常用的方法)Java
- vue中v-on繫結多個方法Vue
- 三個求和公式公式
- Java基礎-設計一個Java類所需的方法(轉)Java
- 在一個xxx.java檔案裡寫多個類(非內部類)Java
- 在catalyst中類方法後面有個屬性
- Java Thread 類相關的幾個核心方法Javathread
- Java面試系列第2篇-Object類中的方法Java面試Object
- Java中的13個原子操作類介紹Java
- Java中可以宣告一個類為Static嗎?Java
- JAVA 兩個類同時實現同一個介面的方法Java
- Java多執行緒12:ReentrantLock中的方法Java執行緒ReentrantLock
- Java的方法Scanner類Java
- Android多媒體框架中幾個重要的類Android框架
- 用java.util.Collections中的sort方法對兩個類的物件進行排序Java物件排序
- JAVA類中透過Servlet操作JSP中Session變數方法JavaServletJSSession變數
- Java - 24 類變數和類方法Java變數
- Java中將多個Map扁平化為單個MapJava
- java中String類常用方法的使用與例項Java
- java多型抽象類例項Java多型抽象
- Java類的多型機制Java多型