遇到多个构造器参数考虑用构建器(Builder)


如果一个对象带有多个参数,程序员一般采用重叠构造器模式。但是该方法的缺点是,如果参数很长,客户端代码不仅很难编写,同时可读性也很差。

第二种替代方案:Java Beans。类中提供一个无参构造方法和对属性的mutator方法。该方法的缺点是容易线程安全问题。

第三种方案就是Builder模式。该方案既保证了重叠构造器模式的安全性,又保证像JavaBeans模式那样好的可读性。

考虑一个例子,一款食物产品通常附属有营养标识,有必须的,也有可选的。比如脂肪,钠,碳水化合物,加路里等。

下面用Builder模式来构造一个营养标识类(NutritionFacts):


// Builder Pattern
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;

	// nested builder
	public static class Builder {
		// Required parameters
		private final int servingSize;
		private final int servings;

		// optional parameters - initialized to default values

		private int calories = 0;
		private int fat = 0;
		private int carbohydrate = 0;
		private int sodium = 0;

		public Builder(int servingSize, int servings) {
			this.servingSize = servingSize;
			this.servings = servings;
		}

		public Builder calories(int val) {
			calories = val;
			return this;
		}

		public Builder fat(int val) {
			fat = val;
			return this;
		}

		public Builder carbohydrate(int val) {
			carbohydrate = val;
			return this;
		}

		public Builder sodium(int val) {
			sodium = val;
			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;
	}

	@Override
	public String toString() {
		return "NutrionFacts[servingSize:" + servingSize + ",servings:"
				+ servings + ",fat:" + fat + ",calories:" + calories
				+ ",sodium:" + sodium + ",carbohydrate:" + carbohydrate + "]";
	}

	public static void main(String args[]) {

		NutritionFacts nf = new NutritionFacts.Builder(5, 10).calories(1)
				.fat(2).carbohydrate(3).build();	// by default sodium = 0

		System.out.println(nf);
	}

}

模式在Android SDK中也有应用。比如我们最熟悉的警告框-AlertDialog,该类就嵌套了一个共有的静态Builder类。如下:

 public static class Builder {
        private final AlertController.AlertParams P;
        private int mTheme;
        
        /**
         * Constructor using a context for this builder and the {@link AlertDialog} it creates.
         */
        public Builder(Context context) {
            this(context, com.android.internal.R.style.Theme_Dialog_Alert);
        }

        /**
         * Constructor using a context and theme for this builder and
         * the {@link AlertDialog} it creates.
         */
        public Builder(Context context, int theme) {
            P = new AlertController.AlertParams(context);
            mTheme = theme;
        }
        
        /**
         * Set the title using the given resource id.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setTitle(int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }
        
        /**
         * Set the title displayed in the {@link Dialog}.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }
        
        /**
         * Set the title using the custom view {@code customTitleView}. The
         * methods {@link #setTitle(int)} and {@link #setIcon(int)} should be
         * sufficient for most titles, but this is provided if the title needs
         * more customization. Using this will replace the title and icon set
         * via the other methods.
         * 
         * @param customTitleView The custom view to use as the title.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setCustomTitle(View customTitleView) {
            P.mCustomTitleView = customTitleView;
            return this;
        }
        
        /**
         * Set the message to display using the given resource id.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setMessage(int messageId) {
            P.mMessage = P.mContext.getText(messageId);
            return this;
        }
        
        /**
         * Set the message to display.
          *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }
        
        /**
         * Set the resource id of the {@link Drawable} to be used in the title.
         *
         * @return This Builder object to allow for chaining of calls to set methods
         */
        public Builder setIcon(int iconId) {
            P.mIconId = iconId;
            return this;
        }
        
        /**
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值