Написал в конструкторе 30 параметров, босс хотел выругаться, когда увидел

Java

Эта статья размещена в личном блоге Yugong Wants to Move Mountains по адресу www.javachat.cc.

Эта статья основана на второй статье книги «Эффективная Java»;

предисловие

В общем, если мы напишем один или два параметра, то будет нормально, если семь или восемь, то будет немного неудобно. Если написать десяток? Нима, неудобно, я помедленнее.

В результате родился новый метод и стратегия. Это режим построителя, когда в методе построения слишком много параметров, удобно создать объект класса. Таким образом, центральная тема этой статьи резюмируется в одном предложении:Когда в конструкторе слишком много параметров, рекомендуется использовать режим построителя

Поскольку рекомендуется использовать режим построителя, давайте проанализируем их один за другим и проанализируем недостатки отказа от использования режима построителя.

1. Недостатки традиционных методов

1. Масштабируемый метод построения

Метод масштабируемой конструкции является наиболее распространенным, который мы обычно пишем, см. код ниже;

public class Student {
 private int id; //必要
 private String name;//必要
 private int age; //可选
 private int sclass; //可选
 private int height;//可选
 private float weight;//可选
 private float score;//可选
 //构造函数1:默认构造方法
 public Student() {};
 //构造方法2:必要字段构造方法
 public Student(int id, String name) {
  this.id = id;
  this.name = name;
 }
 //构造方法3:全部字段构造方法
 public Student(int id, String name, int age, int sclass, int height, float weight, float score) {
  super();
  this.id = id;
  this.name = name;
  this.age = age;
  this.sclass = sclass;
  this.height = height;
  this.weight = weight;
  this.score = score;
 }
}

Далее, если мы хотим создать класс Student, мы обычно создаем его так, см. следующий код:

public class Main {
 public static void main(String[] args) {
  //1、可伸缩构造方法
  Student student1 = new Student();
  Student student2 = new Student(1,"愚公要移山");
  Student student3 = new Student(2,"愚公要移山",18,1,175,120,99);
 }
}

Сейчас мы привели пример с семью полями, который проще понять, а теперь разберем его недостатки:

Недостаток 1: переверните поле, компилятор не сообщит об ошибке

Например, в приведенном выше поле есть вес и оценка, оба типа float.Если вы случайно напишете новый класс Student, компилятор этого не заметит.

Недостаток 2: Трудно понять

Полей здесь всего семь, если их больше десятка, то нужно постоянно проверять в классе Student, что должно быть написано в первом параметре, что действительно хлопотно. Когда пользователь видит этого студента (2, «Югонг хочет свернуть горы», 18, 1, 175, 120, 99), он не может понять, что представляет каждый атрибут поля.

Недостаток 3: параметры, которые вы не хотите устанавливать, но вы должны установить значения

Иногда наш студент просто хочет установить поля идентификатора, имени и возраста, остальные не имеют значения, но этот режим должен установить все значения атрибутов.

Поскольку вышеперечисленные недостатки указаны выше, мы можем подумать о другом способе, а именно о javaBean.

2. режим JavaBean

Сначала посмотрите, как написан режим javaBean.

public class Student {
 private int id; //必要
 private String name;//必要
 private int age; //可选
 private int sclass; //可选
 private int height;//可选
 private float weight;//可选
 private float score;//可选
 //构造函数1:默认构造方法
 public Student() {}
    //getter和setter方法
 public int getId() {return id;}
 public void setId(int id) {this.id = id;}
 public String getName() {return name;}
 public void setName(String name) {this.name = name;}
 public int getAge() {return age;}
 public void setAge(int age) {this.age = age;}
 public int getSclass() {return sclass;}
 public void setSclass(int sclass) {this.sclass = sclass;}
 public int getHeight() {return height;}
 public void setHeight(int height) {this.height = height;}
 public float getWeight() {return weight;}
 public void setWeight(float weight) {this.weight = weight;}
 public float getScore() {return score;}
 public void setScore(float score) {this.score = score;};
}

Этот режим выглядит более удобным, просто установите соответствующие методы геттера и сеттера. Давайте посмотрим, как использовать этот метод для создания класса Student.

public class Main {
 public static void main(String[] args) {
  //2、javaBean模式
  Student student1 = new Student();
  student1.setId(1);
  student1.setName("愚公要移山");
  student1.setSclass(1);
  student1.setWeight(180);
  student1.setHeight(175);
  student1.setScore(100);
  student1.setAge(20);
 }
}

Это выглядит нормально, но я просто напечатал это один за другим сам. Когда я им реально пользуюсь, то знаю, что он такой же отвратительный.А теперь подытожим волну его недостатков.

Недостаток 1: JavaBeans может находиться в несогласованном состоянии во время создания

Сам шаблон JavaBeans имеет серьезные недостатки. Поскольку конструктор разделен на несколько вызовов, во время создания JavaBean Может находиться в несовместимом состоянии. У класса нет возможности обеспечить соответствие, проверяя допустимость аргумента конструктора. Попытка использовать объект в несогласованном состоянии может привести к ошибкам, сильно отличающимся от кода, содержащего ошибку, что затруднит отладку.

Позвольте мне рассказать вам, как я понимаю это.В приведенном выше примере наш объект student1 вызывался методом set много раз, но иногда, когда этот компонент используется, оставшиеся методы установки не были завершены, поэтому вызовите его снова. обнаружил, что один и тот же javaBean представляет два состояния. Так что он находится в противоречивом состоянии.

Недостаток 2: неизменяемость javaBeans не может быть гарантирована

Использование масштабируемого конструктора первого режима не меняет изменчивость после создания экземпляра, все данные являются детерминированными. Безопасность резьбы также гарантируется. Но если предоставляется метод установки, гарантии нет. Например:

public class Main {
 public static void main(String[] args) {
  //2、javaBean模式
  Student student1 = new Student();
  student1.setId(1);
  student1.setName("愚公要移山");
  student1.setSclass(1);
  student1.setWeight(180);
  student1.setHeight(175);
  student1.setScore(100);
  student1.setAge(20);
  System.out.println(student1.getName());
  student1.setName("冯冬冬");
  System.out.println(student1.getName());
 }
}
//输出结果:愚公要移山  冯冬冬

Как видите, мы можем установить имя объекта Student несколько раз, что несовместимо до и после.

Так как первые два имеют различные проблемы. Теперь давайте посмотрим на сегодняшний режим создания тем,

2. режим строителя

Тем не менее, давайте посмотрим, как выглядит режим строителя. Проанализируем его сильные и слабые стороны.

public class Student {
 private int id; // 必要
 private String name;// 必要
 private int age; // 可选
 private int sclass; // 可选
 private int height;// 可选
 private float weight;// 可选
 private float score;// 可选
 public Student(Builder builder) {
  this.id = builder.id;
  this.name = builder.name;
  this.age = builder.age;
  this.sclass = builder.sclass;
  this.height = builder.height;
  this.weight = builder.weight;
  this.score = builder.score;
 }
 public static class Builder {
  private int id; // 必要
  private String name;// 必要
  private int age; // 可选
  private int sclass; // 可选
  private int height;// 可选
  private float weight;// 可选
  private float score;// 可选
  // 必要参数的构造方法
  public Builder(int id, String name) {
   this.id = id;
   this.name = name;
  }
  public Builder setId(int id) {
   this.id = id;
   return this;
  }
  public Builder setName(String name) {
   this.name = name;
   return this;
  }
  public Builder setAge(int age) {
   this.age = age;
   return this;
  }
  public Builder setSclass(int sclass) {
   this.sclass = sclass;
   return this;
  }
  public Builder setHeight(int height) {
   this.height = height;
   return this;
  }
  public Builder setWeight(float weight) {
   this.weight = weight;
   return this;
  }
  public Builder setScore(float score) {
   this.score = score;
   return this;
  }
  // 对外提供的
  public Student build() {
   return new Student(this);
  }
 }
}

Приведенный выше код создает класс Builder внутри, а затем давайте посмотрим, как его использовать.

public class Main {
 public static void main(String[] args) {
  //3、Builder模式
  Student stu = new Student.Builder(1, "愚公要移山")
    .setAge(20)
    .setHeight(175)
    .setSclass(1)
    .setScore(100)
    .setWeight(100).build();
 }
}

Приводятся и недостатки этой книги: интуитивно видно, что объем кода в классе Student значительно увеличился. Но класс Student нам нужно написать только один раз, что дает нам удобство при создании объектов.

Преимущество 1: нет перевернутых полей

Как видно выше, каждый раз, когда добавляется новое значение поля, это делается с помощью set. Имеет преимущества javaBean.

Преимущество 2: гибкие параметры конструкции

Мы пишем необходимые поля и можем выбрать, устанавливать или нет эти необязательные поля.

Преимущество 3: нет противоречивого состояния

При использовании режима построителя создание объектов должно ждать завершения сборки.

Преимущество 4: Гибкое использование

Один построитель можно повторно использовать для создания нескольких объектов. Аргументы построителя можно настроить между вызовами метода сборки для изменения созданного объекта. Построитель может автоматически заполнять некоторые свойства при создании объекта, например серийный номер, который увеличивается при каждом создании объекта.

недостаток:

Для того, чтобы создать объект, сначала должен быть создан его билдер. Хотя затраты на создание этого компоновщика вряд ли будут ощутимы на практике, он может быть проблематичным в критических для производительности ситуациях. Кроме того, шаблон построителя более многословен, чем шаблон телескопического конструктора, поэтому его стоит использовать только в том случае, если аргументов достаточно, скажем, четыре или более.

Однако, если вы начнете с конструктора или статической фабрики и переключитесь на сборщик, устаревший конструктор или статическая фабрика столкнется с неловкой ситуацией, когда класс разовьется до такой степени, что количество параметров выйдет из-под контроля. Так что лучше создать билдер с самого начала.

Суммировать

Если у нас много параметров, то хорошим выбором будет режим Builder, если он относительно небольшой, так как сам Builder является объектом, занимающим определенное количество ресурсов, то лучше использовать масштабируемый или javaBean режим.