1. 程式人生 > 實用技巧 >Java Functional Programming

Java Functional Programming

Java Functional Programming

前提

前兩天看了Java的Functional介面,覺得很是好玩。然後今天在上TDD的課,然後有一個作業(等會聊),需求很簡單,覺得用普通的面向物件寫法沒有什麼進步,也覺得沒啥意思。
於是嘗試用Java寫類似於函數語言程式設計的方法去實現這個需求

需求

  • 不超過8公里時每公里0.8元
  • 超過8公里則每公里加收50%長途費
  • 停車等待時加收每分鐘0.25元

是不是感覺很簡單,一會會就搞完了。我也是這麼感覺的,想一想最近看的Java原始碼,試一試函式式的搞法。

普通實現

這裡暫不關注測試,TDD是一定要先寫測試的.

public class Taxi {
    
    private static final double BASIC_UNIT_PRICE = 0.8;
    private static final int NORMAL_DISTANCE = 8;
    private static final double LONG_DISTANCE_UNIT_PRICE = BASIC_UNIT_PRICE * 0.5;
    private static final double WAIT_TIME_UNIT_PRICE = 0.25;
    // 需求一
    private double getBasicFee(int distance) {
        return distance * BASIC_UNIT_PRICE;
    }
    //需求二
    private double getLongDistanceFee(int distance) {
        return distance - NORMAL_DISTANCE <= 0 ? 0D : (distance - NORMAL_DISTANCE) * LONG_DISTANCE_UNIT_PRICE;
    }
    //需求三
    private double getWaitTimeFee(int waitTime) {
        return waitTime * WAIT_TIME_UNIT_PRICE;
    }
    // 計算方法
    public double calculate(int distance, int waitTime) {
        return getBasicFee(distance) + getLongDistanceFee(distance) + getWaitTimeFee(waitTime);
    }
}

是不是很簡答,一眼就能看明。這麼做沒問題,但是想一想,你工作要一直寫這樣的程式碼是不是很無聊,對於個人成長來說這相當於沒成長呀。
這程式碼畢業生也能寫出來,工作兩年也寫這程式碼???

純函式式實現

public class Taxi {
    
    private static final double BASIC_UNIT_PRICE = 0.8;
    private static final int NORMAL_DISTANCE = 8;
    private static final double LONG_DISTANCE_UNIT_PRICE = BASIC_UNIT_PRICE * 0.5;
    private static final double WAIT_TIME_UNIT_PRICE = 0.25;
    // 需求一
    private ToDoubleTripleIntFunction getBasicFee = (initValue, distance, any) -> initValue + distance * BASIC_UNIT_PRICE;

    // 需求二
    private ToDoubleTripleIntFunction getLongDistanceFee = (initValue, distance, any) ->
            initValue + (distance - NORMAL_DISTANCE <= 0 ? 0D : (distance - NORMAL_DISTANCE) * LONG_DISTANCE_UNIT_PRICE);

    // 需求三
    private ToDoubleTripleIntFunction getWaitTimeFee = (initValue, any, waitTime) -> initValue + waitTime * WAIT_TIME_UNIT_PRICE;
    
    public double calculate(int distance, int waitTime) {
        return getBasicFee
                .thenCompose(getLongDistanceFee)
                .thenCompose(getWaitTimeFee)
                .applyAsDouble(0D, distance, waitTime);
    }
    
    @FunctionalInterface
    private interface ToDoubleTripleIntFunction {
        double applyAsDouble(double f, int t, int u);
        
        default ToDoubleTripleIntFunction thenCompose(ToDoubleTripleIntFunction next) {
            return (double first, int second, int third) -> next.applyAsDouble(applyAsDouble(first, second, third), second, third);
        }
    }

是不是方法都是純函式,沒有一點副作用,寫起來是不是也很優雅。
需求裡的每個實現都是純函式的,我只關注我當前這一步的計算邏輯。具體的組裝放到了外邊。