• 遇到构造器中有多个可选参数时要考虑用构建器


    最近重新阅读《Effectiva Java》,以前是刚写程序不久的时候阅读,读的的时候迷迷糊糊。现在,比以前好多了,读了,明白它的含义。
     
    本文涉及的概念:
    a.重叠构造器
    b.JavaBean
    c.Builder构建器模式
    d.对象状态一致性,唯一性;线程安全
     
    场景:
    1.一个类,有过个构造器,每个构造器的参数数量和顺序是不同的;该构造器有必须的参数
    实现这种需求,有以下两种方式:
    a.使用重叠构造器方式:
     
    public class FoodTelescopingDemo {
    
      private final int id;
      private final String name;
      private final int calories;
      private final int servingSize;
      private final int fat;
      private final String description;
    
      public FoodTelescopingDemo(int id, String name) {
        this(id, name, 0, 0, 0, "default description");
      }
    
      public FoodTelescopingDemo(int id, String name, int calories) {
        this(id, name, calories, 0, 0, "default description");
      }
    
      public FoodTelescopingDemo(int id, String name, int calories, int servingSize) {
        this(id, name, calories, servingSize, 0, "default description");
      }
    
      public FoodTelescopingDemo(int id, String name, int calories, int servingSize, int fat) {
        this(id, name, calories, servingSize, fat, "default description");
      }
    
      /**
       * Main Constructor - actually builds the object
       */
      public FoodTelescopingDemo(int id, String name, int calories, int servingSize, int fat,
          String description) {
        this.id = id;
        this.name = name;
        this.calories = calories;
        this.servingSize = servingSize;
        this.fat = fat;
        this.description = description;
      }
    
      public int getId() {
        return id;
      }
    
      public String getName() {
        return name;
      }
    
      public int getCalories() {
        return calories;
      }
    
      public int getServingSize() {
        return servingSize;
      }
    
      public int getFat() {
        return fat;
      }
    
      public String getDescription() {
        return description;
      }
    
    }
     
        // Use of the Telescoping Constructor
        FoodTelescopingDemo telescopingConstructor1 = new FoodTelescopingDemo(1,
            "My Name");
        // Use the new object
        telescopingConstructor1.toString();
        
        FoodTelescopingDemo telescopingConstructor2 = new FoodTelescopingDemo(1,
            "My Name", 4, 3);
        // Use the new object
        telescopingConstructor2.toString();
        
        FoodTelescopingDemo telescopingConstructor3 = new FoodTelescopingDemo(1,
            "My Name", 4, 3, 34);
        // Use the new object
        telescopingConstructor3.toString();
     
     
    缺点:缺点就是,你在写代码的时候,写构造器的时候,你会很痛苦,你要记住参数的顺序,不能搞错;你要添加多个只是指定了默认参数的构造器。其它人在使用该类的构造器进行实例化的时候,如果选择只需要两个参数的构造器还好,如果选择参数数量大于3个的构造器,那就很痛苦,容易出错。要排好序,记住顺序。
     
    b.使用JavaBeans的方式来实现:
     
    public class FoodBean {
    private int id;
    private String name;
    private int calories;
    private int servingSize;
    private int fat;
    private String description;
     
    public FoodBean(){
     
    }
    public void setId(int id) {
    this.id = id;
    }
    public void setName(String name) {
    this.name = name;
    }
    public void setCalories(int calories) {
    this.calories = calories;
    }
    public void setServingSize(int servingSize) {
    this.servingSize = servingSize;
    }
    public void setFat(int fat) {
    this.fat = fat;
    }
    public void setDescription(String description) {
    this.description = description;
    }
     
    public static void main(String[] args){
    FoodBean bean = new FoodBean();
    bean.setId(10);
    bean.setName("Apple");
     
    }
    }
     
     
     
    缺点:对象的构造过程被分割到了几个调用中,这个对象的状态依赖于set方法的调用。这会出现什么问题?如果把这块代码:
     
    FoodBean bean = new FoodBean();
    bean.setId(10);
    bean.setName("Apple");
     
    添加到同步语句块,确保某一个时刻只有一个线程进行对象构造,那么就没问题。否则,会出现对象的状态不一致。比如,其它线程访问该对象,而该对象的构造过程还没有走完(依赖于set方法的执行)。
    这是最主要的问题,这个问题在线程同步时,容易出现。这样的对象,是线程不安全的。
    另外的缺点,“JavaBeans模式阻止了把类做成不可变的可能”。
     
     
    c.使用构建器来实现:
     
    public class Food {
     
    private final int id;
    private final String name;
    private final int calories;
    private final int servingSize;
    private final int fat;
    private final String description;
     
    public static class Builder {
     
    private int id;
    private String name;
    private int calories;
    private int servingSize;
    private int fat;
    private String description;
     
    public Builder(int id, String name) {
    this.id = id;
    this.name = name;
    }
     
    public Builder Calories(int calories) {
    this.calories = calories;
    return this;
    }
     
    public Builder ServingSize(int servingSize) {
    this.servingSize = servingSize;
    return this;
    }
     
    public Builder Fat(int fat) {
    this.fat = fat;
    return this;
     
    }
     
    public Builder Description(String description) {
    this.description = description;
    return this;
    }
     
    public Food build() {
    return new Food(this);
    }
    }
     
    private Food(Builder builder) {
    id = builder.id;
    name = builder.name;
    calories = builder.calories;
    servingSize = builder.servingSize;
    fat = builder.fat;
    description = builder.description;
    }
     
    public static void main(String[] args) {
     
    Food food = new Food.Builder(10, "Apple").Description("An Apple").ServingSize(20).build();
     
    }
     
    }
     

     

    缺点:为了要创建一个类的实例,要先创建一个构建器对象(Builder实例)。
    优点:在存在多个构造器,每个构造器的参数都比较多,客户端在创建某个构造器时,需要按顺序指定多个参数时,在这样的场景下,可以使用Builder模式。用户在使用Builder创建对象时,会更轻松,构造器参数的语意明确,不用记住顺序。容易阅读,容易写。
     
  • 相关阅读:
    view 与layer
    xcode中create groups 和 create folder reference 的区别
    iOS 9 学习系列:UIStack View (转载)
    使用JQuery插件,排序Gridview的某个字段
    Fixed GridView Header
    在TextBox里面仅仅允许数字,按Enter键进入下一个TextBox
    实现AJAX局部刷新以及PageMethod方法的使用
    用户控件
    JSON的使用
    ASP.NET页面生命周期
  • 原文地址:https://www.cnblogs.com/ttylinux/p/6486858.html
Copyright © 2020-2023  润新知