Android中设计模式-Builder模式

遇到多个构造器参数时要考虑使用构建器

引入:当我们创建对象传递参数的时候,往往通过构造方法来传,如下代码:

public class Person {
    private String name;
    private String id;
    private int age;

    public Person(String name) {
        this.name = name;
    }

    public Person(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public Person(String name, String id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

}

测试类:

public class TestBuilder {
    public static void main(String[] args) {
        Person person=new Person("tom");
        Person person1=new Person("joe","id123");
        Person person2=new Person("lin","id123",24);
    }
}

上面的代码可以使用new构造,也可以用set方法来传入参数。但是不管怎么样 ,如果参数不断的增加,而且增加可选,必选字段,这样使我们的代码很难编写,而且不容易实现。

1、Builder定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

2、使用场景

1、相同的方法,不同的执行顺序,产生不同的事件结果
2、对象比较复杂,参数比较多。

3、uml类图

《Android中设计模式-Builder模式》

4、示例代码:

食品标签中

package bean;

/** * 食品营养标签 */

public class NutritionFacts {
    private final int servingSize;//食品分量
    private final int servings;//食品
    private final int calories;//热量
    private final int fat;//脂肪
    private final int sodium;//钠
    private final int carbohydrate;//碳水化合物

    @Override
    public String toString() {
        return "NutritionFacts{" +
                "servingSize=" + servingSize +
                ", servings=" + servings +
                ", calories=" + calories +
                ", fat=" + fat +
                ", sodium=" + sodium +
                ", carbohydrate=" + carbohydrate +
                '}';
    }

    public static class Builder {
        //必选字段
        private int servingSize;
        private int servings;
        //可选字段,添加默认属性
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        //通过builder模式,给对象添加属性;
        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }
        public Builder calories(int calories) {
            this.calories = calories;
            return this;
        }
        public Builder fat(int fat) {
            this.fat = fat;
            return this;
        }
        public Builder carbohydrate(int carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }
        public Builder sodium(int sodium) {
            this.sodium = sodium;
            return this;
        }
        //返回外部对象
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }
    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

测试代码:

     NutritionFacts nutritionFacts = new NutritionFacts.Builder(240, 8)
                .calories(100)
                .sodium(35)
                .carbohydrate(27)
                .build();

运行结果:

NutritionFacts: NutritionFacts{servingSize=240, servings=8, calories=100, fat=0, sodium=35, carbohydrate=27}

5、Android源码中的Builder模式

Android中Builder模式也是常见的,最熟悉的是Dialog

  AlertDialog.Builder dialog= new AlertDialog.Builder(this);
        dialog.setTitle("title")
                .setMessage("message")
                .create()
                .show();

源码分析:

public class AlertDialog extends AppCompatDialog implements DialogInterface {

    final AlertController mAlert;

      public static class Builder {
        private final AlertController.AlertParams P;
        private final int mTheme;


        public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
        mAlert.setButton(whichButton, text, listener, null);
        }


        public void setIcon(int resId) {
        mAlert.setIcon(resId);
        }

        ......

        public Builder(@NonNull Context context) {
            this(context, resolveDialogTheme(context, 0));
        }


        public Builder(@NonNull Context context, @StyleRes int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));
            mTheme = themeResId;
        }


        @NonNull
        public Context getContext() {
            return P.mContext;
        }


        public Builder setTitle(@StringRes int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }


        public Builder setTitle(@Nullable CharSequence title) {
            P.mTitle = title;
            return this;
        }


        public Builder setCustomTitle(@Nullable View customTitleView) {
            P.mCustomTitleView = customTitleView;
            return this;
        }


        public Builder setMessage(@StringRes int messageId) {
            P.mMessage = P.mContext.getText(messageId);
            return this;
        }


        ......
        //返回AlertDialog对象
         public AlertDialog create() {
            // We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
            // so we always have to re-set the theme
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

        public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }

}

6、总结

与构造器相比,builder的微略优势在于,builder可以有多个可变参数,构造器就像方法一样,只能有一个可变参数。因为builder利用单独
的方法来设置每个参数,你想要多少个可变参数,它们就可以有多少个,直到每个setter方法都有一个可变参数。

Builder模式十分灵活,可以利用单个builder构建多个对象,builder的参数可以在创建对象期间进行调整,也可以随着不同的对象而改变。builder
可以自动填充其些域,例如每次创建对象时自动增加。

简而言之,如果类的构建器或者静态工厂有多个参数,设计这种时,Builder模式就是不错的选择,特别是当大多数参数都是可选的时候。与
使用传统的重叠构造器模式相比,使用builder模式的客户端代码装将更易于阅读和编写,构建器也比JavaBeans更加安全。

ref 《effective java》《Android源码设计模式解析与实战》

    原文作者:PowerFromAndroid
    原文地址: https://blog.csdn.net/androidxiaogang/article/details/80586631
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞