如何用最小代價重構你的構造函數

在重構老項目的過程當中,咱們不難發現常常會有這樣的代碼:構造函數不少(我的認爲超過2個以上的構造函數所屬的類,就有必要進行一番修改了),每每不知道如何維護,遇到版本迭代的時候,若是要修改以前的老代碼則顯的信心不足,只能在裏面加補丁,代碼習慣好點的可能加補丁的時候還會增長一點註釋,代碼習慣差一點的註釋都沒有。時間久了這部分代碼就成了屎山,並且這個類也變的愈來愈難以維護。本文就從幾個維度上教你如何重構相似的場景。程序員

下面是一個支付結果的類,看看相似的代碼風格在你的項目中有沒有(若是真的沒有說明大家的團隊技術水平真的很好,建議點擊右上角關閉本文,不要浪費時間)安全

//支付渠道
interface PayChannel {

}
//銀行渠道
class BankChannel implements PayChannel {

}
//微信
class WxChannel implements PayChannel {

}
//支付寶
class AliPayChannel implements PayChannel {

}
複製代碼
/**
 * 支付結果類
 */
public class PayResult {
    //支付渠道
    private PayChannel payChannel;
    //支付時間
    private Date payDate;
    //訂單總金額
    private Double totalValue;
    //實際支付金額
    private Double paymentValue;
    //用券抵消的金額
    private Double couponValue;
    //貸款支付的金額
    private Double loanValue;

    //銀聯支付 沒有 用券的資格 也沒有用貸款支付的資格
    public PayResult(Date payDate, Double totalValue, Double paymentValue) {
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;

        this.payChannel = new BankChannel();
        this.loanValue = 0.0d;
        this.paymentValue = 0.0d;
    }

    //微信支付沒有貸款支付的能力
    public PayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.payChannel = new WxChannel();
        this.loanValue = 0.0d;
    }


    public PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }

}
複製代碼

能夠看出來PayResult這個類 僅僅有六個字段,可是構造函數就達到了三個。很很差維護。並且一般在項目裏,這樣的基礎類可能用到的地方不少不少,咱們一時半會也不敢隨意大改,怕引起線上故障bash

相似於:微信

public class TestMain {
    public static void main(String[] args) {
        PayResult p1 = new PayResult(new Date(), 3.1d, 3.1d);
        PayResult p2 = new PayResult(new AliPayChannel(), new Date(), 5.2d, 3.2d, 3.1d, 0.1d);
        PayResult p3 = new PayResult(new Date(), 3.1d, 2.1d, 1.0d);

    }
}
複製代碼

調用的地方太多,壓根不敢隨便大改。畢竟重構的首要條件是不要引起線上故障。那麼有沒有較爲溫和的方式可以優化一下這樣的代碼呢? 畢竟其實上述的構造函數裏面的重複代碼也挺多的,構造函數越多,重複代碼的傷害就越大。碰到這種狀況,咱們一般會利用構造函數連接來完成重構,就是指:特殊的構造函數會調用更通用的構造函數,直到到達最後一個構造函數。 講白了,其實就是讓多餘的構造函數之間經過this.構造函數 來進行一個收斂,決絕重複代碼,僅此而已。這樣改起來,不會形成侵入性過大,維護成本也較小。函數

例如:微信支付

//銀聯支付 沒有 用券的資格 也沒有用貸款支付的資格
    public PayResult(Date payDate, Double totalValue, Double paymentValue) {
        this(new BankChannel(), payDate, totalValue, paymentValue, 0.0d, 0.0d);
    }

    //微信支付沒有貸款支付的能力
    public PayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        this(new WxChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);

    }

    //這個就是全包構造函數了 構造函數最全的就能夠稱之爲全包構造函數,當咱們的構造函數過多的時候
    //就能夠將多餘的構造函數都最終指向咱們的全包構造函數,這是一個收斂的過程
    public PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }
複製代碼

改完之後就很簡單,咱們將咱們的構造函數進行了統一的收斂,這在業務負載,改動頻繁的場景中會變的十分好用, 不會由於增長刪除或者變動了某些字段而引起大面積改動。優化

若是是一個有代碼潔癖的人,改到這裏也會以爲不舒服,還想繼續改。由於這樣改完雖然可以部分解決構造函數複雜,維護成本巨大的問題,可是代碼的可讀性卻沒有改觀。ui

對於構造函數來講,可讀性很是很是重要。本質上來講,若是一個類的構造函數越多,那麼程序員犯錯的可能性就越高,由於你構造函數太多了,多到你的構造函數自己沒法有效和高效的表達你的意圖。this

並且對於不少終年累月的老項目來講,不少構造函數甚至都過期了,根本沒人用。可是由於可讀性的問題,敢刪掉他們的人很少。spa

下面繼續介紹一種方法,看看能不能在改動不大的狀況下,重構咱們的代碼,把可讀性給提升一下。

//銀聯支付
    public static PayResult createUnionPayResult(Date payDate, Double totalValue, Double paymentValue) {
        return new PayResult(new BankChannel(), payDate, totalValue, paymentValue, 0.0d, 0.0d);
    }

    //微信支付
    public static PayResult createWxPayResult(Date payDate, Double totalValue, Double paymentValue, Double couponValue) {
        return new PayResult(new WxChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);
    }

    //支付寶支付
    public static PayResult createAliPayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        return new PayResult(new AliPayChannel(), payDate, totalValue, paymentValue, couponValue, 0.0d);
    }


    //注意這個時候咱們的全包構造函數 變成了private
    private PayResult(PayChannel payChannel, Date payDate, Double totalValue, Double paymentValue, Double couponValue, Double loanValue) {
        this.payChannel = payChannel;
        this.payDate = payDate;
        this.totalValue = totalValue;
        this.paymentValue = paymentValue;
        this.couponValue = couponValue;
        this.loanValue = loanValue;
    }
複製代碼

增長了幾個靜態的create 函數,而後將咱們的全包構造函數進行收斂 設置爲private. 極大的限制了調用者的權限, 從而在必定程度上能夠避免程序員的犯錯。 並且這種改動也不會傷筋動骨,對於老的代碼調用處來講,只要更換一下函數名便可:

public class TestMain {
    public static void main(String[] args) {
        PayResult p1 =  PayResult.createUnionPayResult(new Date(), 3.1d, 3.1d);
        PayResult p2 =  PayResult.createAliPayResult(new AliPayChannel(), new Date(), 5.2d, 3.2d, 3.1d, 0.1d);
        PayResult p3 =  PayResult.createWxPayResult(new Date(), 3.1d, 2.1d, 1.0d);

    }
}
複製代碼

這樣看起來,不但可讀性大大提高,安全性也較好,不再用擔憂有其餘同事用錯了。

相關文章
相關標籤/搜索