《Effective Java》 创建和销毁对象之构造器参数较多时考虑构建器(建造者模式)

        在类中,静态工厂和构造器有一个共同的局限性:它们不能很好的扩展到大量的可选参数。

        例如:当构造器的参数可能有1,2,···,8,···等,且构造器的个数不唯一。

(1)重叠构造器模式

        在这种情况下开发者习惯采用重叠构造器模式,即提供只有一个参数的构造器,提供只有两个参数的构造,以此类推,最后一个构造器含有所有的可选参数。这种方式可行,但是当许多参数时,客户端代码会很难编写,并且阅读性很差。

(2)JavaBeans模式

        在这种模式下,调用一个无惨构造函数来创建对象,然后调用setter方法来设置每个必要的参数,以及可选参数。这种模式弥补了重叠构造器模式的不足,创建实例容易,且代码阅读性较高,但是JavaBeans模式自身有很严重的缺点,当构造过程被分为几个部分完成时,可能会产生不一致的状态,类无法通过检验构造器的参数来保证一致性。第二个缺点在于无法将类变成不可变类,这就需要开发者付出额外的努力来保证线程安全。

(3)Builder模式

        该模式可以保证向重叠构造器那样的安全性,又可以保证像JavaBeans模式那样的可读性。 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后客户端调用无参的builder方法来生成不可变对象。注:这里的builder是它构建的类的静态成员类。如下案例:

public class NutritionFacts {
	private final int servingSize;		
    private final int servings;			
    private final int calories = 0;		
    private final int fat = 0;		
    private final int sodium = 0;		
    private final int carbohydrate = 0;	
    
    public static class Builder {
    	//必填参数
        private final int servingSize;
      	private final int servings;
      	//可选参数 - 默认参数值初始化
      	private int calories = 0;
      	private int fat = 0;
      	private int sodium = 0;
      	private int carbohydrate = 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 sodium(int val) {
			sodium = val;
			return this;
		}
		public Builder carbohydrate(int val) {
			carbohydrate = 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;
		}
    }

注:这里的NutritionFacts 是不可变的,所有的不可变参数都单独放在一个位置,builder的setter的方法返回builder本身,以便于链式调用。调用代码如下:

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值