1. 程式人生 > >Android_物件的建立And建造者模式

Android_物件的建立And建造者模式

作為一個普通的Android的上層開發,最早引以為榮的事情就是自己實現了某些效果,完成了某些自定義控制元件自豪,會使用當前較為流行的開源框架而自豪,比如RxJava retrofit fresco…..

這些天也是不是也反思為毛招聘Android工程師,技能點都是JAVA基本功,深入JVM 資料結構和演算法,說好的招Android開發呢!

地基打不好,樓層蓋不高
曾經浪費掉的光陰,只能今天來彌補,於是最近在閱讀大神推薦的Effective Java.

提高程式碼嚴謹性,提高程式設計思想,copy 永遠是copy ,使用一直是使用,思想是別人demo給不了你的!
–2016年03月20日

  • -靜態工廠的使用
    有些時候我們需要用靜態工廠的方法代替構造器,

  • 靜態工廠,例項物件的時候程式碼更容易閱讀,他們有名稱

  • 靜態工廠,不必再每次呼叫他們的時候都建立一個新的物件
  • 靜態工廠,可以返回原返回型別的任何子型別的物件
  • 如下程式碼片段
public class HashMapFactory {
    private HashMapFactory() {

    }

    public static <K, V> HashMap<K, V> newInstance() {
        return new HashMap<K, V>();
    }
}

我們建立了一個Map的工廠類,於是我們在使用的時候就可以非常便捷

  Map<String, String> mTestString;
        Map<String, Integer> mTestInteger;

        mTestInteger = HashMapFactory.newInstance();
        mTestString = HashMapFactory.newInstance();

        mTestInteger.put("INTEGER", 12);
        mTestInteger.put("INTEGER1"
, 13); mTestString.put("String", "sfsfs"); mTestString.put("String1", "哈哈哈哈");

不管你建立何種型別的map都只需要,newInstance即可

遇到多個構造器引數的時候考慮用builder pattern

是將一個複雜的物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。

我們Android程式設計師其實經常碰見這類程式碼,比如我們建立一個dialog的時候,

 //顯示基本的AlertDialog   
     private   void  showDialog(Context context) {  
        AlertDialog.Builder builder =  new  AlertDialog.Builder(context);  
        builder.setIcon(R.drawable.icon);  
        builder.setTitle( "Title" );  
        builder.setMessage( "Message" );  
        builder.setPositiveButton( "Button1" ,  
                 new  DialogInterface.OnClickListener() {  
                     public   void  onClick(DialogInterface dialog,  int  whichButton) {  
                        setTitle( "點選了對話方塊上的Button1" );  
                    }  
                });  
        builder.setNeutralButton( "Button2" ,  
                 new  DialogInterface.OnClickListener() {  
                     public   void  onClick(DialogInterface dialog,  int  whichButton) {  
                        setTitle( "點選了對話方塊上的Button2" );  
                    }  
                });  
        builder.setNegativeButton( "Button3" ,  
                 new  DialogInterface.OnClickListener() {  
                     public   void  onClick(DialogInterface dialog,  int  whichButton) {  
                        setTitle( "點選了對話方塊上的Button3" );  
                    }  
                });  
        builder.create().show();  // 構建AlertDialog, 並且顯示
    } 

上面的程式碼我們再熟悉不過了,我們要彈出一個對話方塊,
對話方塊中有很多引數,並不是我們構造的時候都要傳入的,他分為
必傳引數和可選引數,比如context 是必傳的,剩下的title和icon 和message都是可選的還有按鈕的數量,

再比如我們用的網路請求庫retrofit,可以選擇設定header,gosonfactory ,等

為了更好的理解建造者模式中的各個角色,我們就仿造android的alertdialog的寫法,自己做一個建造者,來呼叫下

首選我們寫一個House類,我們來蓋房子
因為我們要用建造者來例項化不同的房子,所以,

  1. 我們House的構造就必須私有化,不提供給外界呼叫,我們呼叫的時候直接是用類名,呼叫的建造者的build方法,所以我們需要在類的內部提供一個static的建造者
  2. 將靜態的建造者提供例項化各種屬性類別的方法,返回當前的建造者
  3. 最後提供一個公開的build方法返回設定好各種屬性的當前的物件

    我們在程式碼中看一下分工,

public class House {
    // 必選的引數
    private String foundation;
    private String material;

    // 可選的引數
    private String bigDoor;
    private String setp;
    private String ceilingLamp;

    // 內部提供一個靜態的builder類,提供引數的設定,以及返回例項
    public static class Builder {
        private String foundation;
        private String material;

        // 可選引數賦預設值
        private String bigDoor = "普通大門";
        private String setp = "普通臺階";
        private String ceilingLamp = "普通吊燈";

        /**
         * 構造引數中傳遞必選引數
         *
         * @param foundation
         * @param material
         */
        public Builder(String foundation, String material) {
            this.foundation = foundation;
            this.material = material;
        }

        // 可選引數的可選builder方法

        public Builder bigDoor(String bigDoor) {
            this.bigDoor = bigDoor;
            return this;
        }

        public Builder setP(String setp) {
            this.setp = setp;
            return this;
        }

        public Builder ceilingLamp(String ceilingLamp) {
            this.ceilingLamp = ceilingLamp;
            return this;
        }

        // 上述必選和可選的引數全部配置完畢,最後開始建造房子,返回當前房子物件
        public House build() {
            return new House(this);
        }

    }

    // 建構函式私有化返回當前的物件
    private House(Builder builder) {
        this.foundation = builder.foundation;
        this.material = builder.material;
        this.bigDoor = builder.bigDoor;
        this.setp = builder.setp;
        this.ceilingLamp = builder.ceilingLamp;
    }
  }

最後我們在我們的類中使用下我們的建造者,給我和你分別建立一個house,

  private static void testBuilderPattern() {
        // 使用的時候因為我們的類已經私有化建構函式,所以只能通過New 出來當前類的建造者來配置,和builder
        Car mCar = new Car.Builder("高階輪胎", "進口引擎", "24k金方向盤")
                .graffiti("全裸塗鴉")
                .sticker("豪放貼紙")
                .build();

        // 不傳遞可選引數
        Car otherCar = new Car.Builder("普通輪胎", "大眾引擎", "拖拉機改造方向盤")
                .build();

        House mHouse = new House.Builder("350平米地基", "全進口材料")
                .bigDoor("鍍金雙開大門")
                .ceilingLamp("南非鑲鑽吊燈")
                .setP("進口大理石臺階")
                .build();

        House otherHouse = new House.Builder("10平米廁所旁地基", "國內高含量超標材料")
                .bigDoor("破大門")
                .ceilingLamp("普通燈泡")
                .setP("藍翔挖掘的紅磚臺階")
                .build();
  }

這樣就一路瞭然,我們的必選引數通過建造者的建構函式傳入,可選引數分別呼叫了當前引數建造方法,在全部的引數配置完畢之後,我們呼叫下build()方法就返回了當前的class物件,

?為什麼呼叫build方法沒new當前物件就能返回當前的class呢
答案就是,我們build方法在內部呼叫了 new Instance()方法.並且把配置好全部屬性的builder傳入到構造中,並且把builder的屬性給我們的class屬性賦值,

   // 配置完畢執行build方法返回當前具備屬性的物件
        public Car build() {
            // 這呼叫了下面的私有構造方法,接受當前配置好屬性的builder
            return new Car(this);
        }

    // 這裡傳入了配置好屬性的builder給我們的class屬性賦值,
    private Car(Builder builder) {
        this.engine = builder.engine;
        this.graffiti = builder.graffiti;
        this.sticker = builder.sticker;
        this.tires = builder.tires;
        this.wheel = builder.wheel;
    }

好了我們看下結果,我的房子和我的車都是什麼屬性
這裡寫圖片描述

總結 :如果類的構造器或者靜態工廠中具有多個引數,設計這種類,Builder模式就是個不錯的選擇,特別有很多可選引數或者元素的時候,使用傳統的構造器或者過載,並沒有Builder模式簡單讓客戶端程式碼更容易閱讀和編寫…

謝謝您的閱讀!!