4種Java類多參數(shù)構(gòu)建模式

最近在實際項目中遇到了多參數(shù)初始化問題。如何在模塊初始化時傳入多個參數(shù)(5個以上)?如何更安全?如何更靈活?如何可擴展?如何簡化調(diào)用代碼?如何增強可讀性?我在面試中也常提出這樣的問題。以上內(nèi)容如果讀過《Efective Jave》會很容易在第二章找到答案。

《Efective Jave》中主要介紹了 3 種多參數(shù)構(gòu)建方法,我在項目里還用到了第 4 種。下面一一介紹。

0x00 簡單、常用:重疊構(gòu)造器

代碼示例:

public class A {
    private int v1;
    private int v2;
    private int v3;
    private int v4;
    private int v5;
    
    public A(int v1) { this(v1, DEFUALT_V2)}
    public A(int v1, int v2) { this(v1, v2, DEFUALT_V3)}
    public A(int v1, int v2, int v3) { this(v1, v2, v3, DEFUALT_V4)}
    public A(int v1, int v2, int v3, int v4) { this(v1, v2, v3, v4, DEFUALT_V5)}
    public A(int v1, int v2, int v3, int v4, int v5) {
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;
        this.v4 = v4;
        this.v5 = v5;
    }
}

優(yōu)點:

  1. 邏輯、層級清晰明了。適合參數(shù)層級關(guān)系明確的類,如 Android 里的 View。

缺點:

  1. 參數(shù)增多時,可讀性變差
  2. 如示例所示,如果連續(xù)傳入多個同樣類型的變量,容易把順序弄錯
  3. 靈活性不足,無法指定初始化特定幾個參數(shù)

0x01 簡單、靈活:重復(fù) set 方法

代碼示例:

public class B {
    private int v1 = DEFAULT_V1;
    private int v2 = DEFAULT_V2;
    private int v3 = DEFAULT_V3;
    private int v4 = DEFAULT_V4;
    private int v5 = DEFAULT_V5;
    
    public B() {}
    public void setV1(int val) { v1 = val; }
    public void setV2(int val) { v2 = val; }
    public void setV3(int val) { v3 = val; }
    public void setV4(int val) { v4 = val; }
    public void setV5(int val) { v5 = val; }
}

優(yōu)點:

  1. 簡單
  2. 靈活,支持定制式初始化,即參數(shù)可選,如果不需要自定義的變量可以直接不給初始化方法
  3. 支持動態(tài)改變參數(shù),set 方法也可以在程序運行的任何階段調(diào)用

缺點:

  1. 如果變量的需要按一定順序初始化,那么這種調(diào)用方式將帶來風(fēng)險。實際項目被這個坑過。提供外部的接口最好在編寫時排除這種漏洞的隱患
  2. set 方法可在任何時間調(diào)用,更改變量的值。和缺點 1 同理,如果變量耦合了其他邏輯,那么隨時可調(diào)用 set 方法就是不安全的。

0x02 安全、可讀:Builder 構(gòu)建器

代碼示例

public class C {
    private int v1;
    private int v2;
    private int v3;
    private int v4;
    private int v5;
    
    public static class Builder {
        private int v1 = DEFAULT_V1;
        private int v2 = DEFAULT_V2;
        private int v3 = DEFAULT_V3;
        private int v4 = DEFAULT_V4;
        private int v5 = DEFAULT_V5;

        public Builder(int v1) { this.v1 = v1; return this;}
        public Builder v2(int val) { this.v2 = val; return this; }
        public Builder v3(int val) { this.v3 = val; return this; }
        public Builder v4(int val) { this.v4 = val; return this; }
        public Builder v5(int val) { this.v5 = val; return this; }
        public C build() { return new C(this); }
    }

    private C(Builder builder) {
        this.v1 = builder.v1;
        this.v2 = builder.v2;
        this.v3 = builder.v3;
        this.v4 = builder.v4;
        this.v5 = builder.v5;
    }
}
// Usage:
// C c = new C.Builder(1).v2(2).v3(3).v4(4).v5(5).build();

優(yōu)點:

  1. 靈活,支持定制式初始化
  2. 可讀性強,參見 Android 的 Animator 類,一個語句完成類的初始化和調(diào)用
  3. 可以在 build() 方法內(nèi)統(tǒng)一進(jìn)行參數(shù)校驗,為《Ecfective Java》推薦方法

缺點:

  1. 復(fù)雜,構(gòu)建所需代碼行數(shù)增加
  2. 參數(shù)在傳入時為確定參數(shù),不支持動態(tài)改變

0x03 實時參數(shù):Provider 模式

該方法借鑒了 Builder 構(gòu)建器,但是將構(gòu)建器獨立于類外,同時提供實時獲取的接口。

public class D {
    private int v1;
    private int v2;
    private int v3;
    private int v4;
    private int v5;
    
    public interface Provider {
        public int getV1();
        public int getV2();
        public int getV3();
        public int getV4();
        public int getV5();
    }

    public D(Provider provider) {
        this.v1 = provider.getV1();
        this.v2 = builder.v2;
        this.v3 = builder.v3;
        this.v4 = builder.v4;
        this.v5 = builder.v5;
    }
}
// Usage:
// public class IProvider implement D.Provider {
//        @Override
//        public int getV1() { return val; }
//        @Override
//        public int getV2() { return val; }
//        @Override
//        public int getV3() { return val; }
//        @Override
//        public int getV4() { return val; }
//        @Override
//        public int getV5() { return val; } 
// }
// D d = new D(new IProvider());

優(yōu)點:

  1. 借鑒了 Builder 構(gòu)建器的優(yōu)點,隔離了參數(shù)傳入方法和初始化方法
  2. Provider 由調(diào)用方實現(xiàn),使動態(tài)參數(shù)的傳入變?yōu)榭赡?/li>
  3. 調(diào)用節(jié)點只需要調(diào)用一行語句,初始化參數(shù)的準(zhǔn)備移至他處。這種場景需求可能發(fā)生在一個核心類的 initAll() 方法中,調(diào)用者需要在該方法內(nèi)先后初始化十幾個模塊。如果每個模塊都要寫十行代碼那就非常恐怖了。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,586評論 19 139
  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法,而不是構(gòu)造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法,并非Fa...
    孫小磊閱讀 2,184評論 0 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,109評論 25 709
  • 你是夏日冰涼汽水里咕咚咚的氣泡,說穿了也沒什么味道,卻是所有的清涼與暢快; 你是夜路上一縷微醺的晚風(fēng),驅(qū)不開夜色照...
    吉莉安閱讀 323評論 0 1
  • 前面我們講了,在進(jìn)攻端大致有四種狀態(tài)或者階段:快攻階段、過渡階段、陣地進(jìn)攻階段、不打戰(zhàn)術(shù)階段(二次進(jìn)攻、對方主動性...
    籃球伊甸園閱讀 388評論 0 0

友情鏈接更多精彩內(nèi)容