【Java笔记(49)】EffectiveJava第二条之建造者模式(建造者模式)

一、大白话

  • 静态工厂和构造有个共同的局限性:不能很好的拓展到大量的可选参数中。
  • 一般采用 重叠构造器模式JavaBeans模式,但这两种模式都各有缺陷。
  • 建造者模式既能保证重叠构造器模式那样的安全性,也能拥有像JavaBeans模式那样的可读性。
  • Buidler模式是采用一个静态类Builder,来对属性进行赋值,然后再通过调用builder方法将属性值传递给外部类(真实的类)创建对象。

二、三种模式的优缺点

1、重叠构造器模式

  • 直接看代码,当你的构造器有2个参数的时候,会调用3个的,接着调用4个的…
  • 依次类推到每个参数都有初始值,这就是重叠构造器模式
public class NutritionFacts {
    private final int servingSize;  // (mL)            required
    private final int servings;     // (per container) required
    private final int calories;     // (per serving)   optional
    private final int fat;          // (g/serving)     optional
    private final int sodium;       // (mg/serving)    optional
    private final int carbohydrate; // (g/serving)     optional

    //两个参数狗构造器
    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    //三个参数构造器
    public NutritionFacts(int servingSize, int servings,
                          int calories) {
        this(servingSize, servings, calories, 0);
    }

    //四个参数构造器
    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    //五个参数构造器
    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    //六个参数构造器
    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize  = servingSize;
        this.servings     = servings;
        this.calories     = calories;
        this.fat          = fat;
        this.sodium       = sodium;
        this.carbohydrate = carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola =
                new NutritionFacts(240, 8, 100, 0, 35, 27);
    }
}

① 优点

  • 安全性还可以,这里指的安全性是构造器的对象A,和后面代码的对象A一致。

② 缺点

  • 从代码可以看出,非常的繁琐,这里仅仅是6个参数就需要这么多代码,可想而知在10个参数,20个参数的时候,就失去控制了。
  • 在许多参数的时候,客户端代码会很难编写,并且难以阅读。
  • 在传参的时候,如果一不小心将参数的顺序颠倒,会导致错误。

2、JavaBeans模式

  • JavaBeans模式是我们的学习JavaSE是最常用的一种模式,也是最容易编写的一种模式,采用无参构造器和setter方法来设置每一个参数。
public class NutritionFacts {
    private int servingSize = -1; 
    private int servings = -1; 
    private int calories = 0;
    private int fat = 0;
    private int sodium = 0;
    private int carbohydrate = 0;

    public NutritionFacts() { }

    // Setters
    public void setServingSize(int val) { servingSize = val; }

    public void setServings(int val) { servings = val; }

    public void setCalories(int val) { calories = val; }

    public void setFat(int val) { fat = val; }

    public void setSodium(int val) { sodium = val; }

    public void setCarbohydrate(int val) { carbohydrate = val; }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts();
        cocaCola.setServingSize(240);
        cocaCola.setServings(8);
        cocaCola.setCalories(100);
        cocaCola.setSodium(35);
        cocaCola.setCarbohydrate(27);
    }
}

① 优点

  • 可读性高

② 缺点

  • 在构造过程中JavaBean可能出一不一致状态:这里的不一致状态笔者的理解是,在构造的过程中,需要设置设置设置属性,在每一次设置的时候,都是不一样的状态。并且在设置的过程中,如果有客户端要来访问,那么访问到的可能是缺少属性的对象。
  • JavaBeans模式使得把类做成不可变的可能性不复存在:这里的意思是有了set方法,那么构造出来的对象,就能被修改,那么程序员需要付出额外的努力来保证线程安全。

3、建造者模式

  • 建造者模式是使用一个内部类进行属性的初始化,再通过一个buile()方法进行对象的创建。
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 void main(String[] args) {
        //当内部类为静态的时候,可以直接通过
        NutritionFacts cocaCola = new NutritionFacts.Builder(240 , 8).calories(100).sodium(35).carbohydrate(27).build();
        System.out.println(cocaCola);
    }

    //静态内部类
    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;
    }
}

① 优点

  • 参数在设置的时候拥有了名字,可读性强。
  • 安全性高,生成的对象拥有不可变性。

② 缺点

  • 在参数较少的时候不适合使用

三、总结

  • 如果类在后期需要添加参数,那么一开始就需要使用构建者模式,如果使用构造器或静态工厂方法,那么后期会无法控制。
  • 如果类的构造器或静态工厂方法需要多个参数,那么优先考虑Builder模式
  • 特别是大多数参数可选或类型相同时,使用Buider模式,易于阅读和安全性高。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值