Удобство по сравнению с множеством единиц Swift - PullRequest
1 голос
/ 11 марта 2020

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

В этой реализации у меня есть два инициализатора для класс

class Person1 {
  var name: String
  var age: Int
  var nationality: String

  init(name: String, age: Int,  nationality: String) {
    self.name = name
    self.age = age
    self.nationality = nationality
  }

  init(name:String, age: Int) {
    self.name = name
    self.age = age
    self.nationality = "Canadian"
  }
}

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

  let p1 = Person1(name: "Stewart", age: 40)

Если я заменю этот второй инициализатор следующим удобным инициализатором,

convenience init(name: String, age: Int) {
    self.init(name: name, age: age, nationality: "Canadian")
}

, я могу создать тот же экземпляр таким же образом и получить тот же результат. Так в чем же разница? Мне трудно найти хороший пример, где удобный инициализатор - единственный способ выполнить sh создание конкретного экземпляра класса, который не может быть выполнен вторым инициализатором, как я делал в первом примере.

1 Ответ

1 голос
/ 11 марта 2020

В действительности наличие двух ваших инициализаторов - это Bad Code ™. Как сказал Лео Дабус, express точный пример, использующий наиболее подходящую языковую функцию Swift, - использовать значение параметра по умолчанию.

class Person1 {
  var name: String
  var age: Int
  var nationality: String

  init(
    name: String,
    age: Int,
    nationality: String = "Canadian"
  ) {
    self.name = name
    self.age = age
    self.nationality = nationality
  }
}

Удобный инициализатор - это то, что вы используете, когда существует другой инициализатор, который спасет вас от дублирования кода.

Например, допустим, вы добавили суперкласс с обязательным init:

class Person0 {
  var name: String
  var age: Int

  required init(
    name: String,
    age: Int
  ) {
    self.name = name
    self.age = age
  }
}

Вы не можете просто сделать это; Swift не считает, что это удовлетворяет требованию:

class Person1: Person0 {
  var nationality: String

  required init(
    name: String,
    age: Int,
    nationality: String = "Canadian"
  ) {
    self.nationality = nationality
    super.init(
      name: name,
      age: age
    )
  }
}

Вместо этого вы можете либо дублировать, например так:

  required init(
    name: String,
    age: Int
  ) {
    nationality = "Canadian"
    super.init(
      name: name,
      age: age
    )
  }

  init(
    name: String,
    age: Int,
    nationality: String
  ) {
    self.nationality = nationality
    super.init(
      name: name,
      age: age
    )
  }

… или использовать один назначенный инициализатор, который фактически выполняет работать и переслать требуемый init вместе с ним:

  required convenience init(
    name: String,
    age: Int
  ) {
    self.init(
      name: name,
      age: age,
      nationality: "Canadian"
    )
  }

  init(
    name: String,
    age: Int,
    nationality: String
  ) {
    self.nationality = nationality
    super.init(
      name: name,
      age: age
    )
  }

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

Вы всегда можете дублировать код. Удобный инициализатор никогда не будет единственным способом. В самых простых случаях, как я показываю здесь, у вас будет только частичная строка дублирования для каждого инициализатора. Это не имеет большого значения. Но дедупликация накапливается с наследованием.

Если ваш подкласс обеспечивает реализацию всех своих инициализаторов, назначенных суперклассом, - либо наследуя их согласно правилу 1, либо предоставляя пользовательскую реализацию как часть его определение - тогда он автоматически наследует все удобные инициализаторы суперкласса. - https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

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

например

Person2(name: "Terrance Phillip", age: 42)

компилирует, из этого:

class Person2: Person1 {
  var flag: String

  override convenience init(
    name: String,
    age: Int,
    nationality: String
  ) {
    self.init(
      name: name,
      age: age,
      nationality: nationality,
      flag: "??"
    )
  }

  init(
    name: String,
    age: Int,
    nationality: String,
    flag: String
  ) {
    self.flag = flag
    super.init(
      name: name,
      age: age,
      nationality: nationality
    )
  }
}

Это также тот же человек, что и этот:

Person3()

… учитывая это:

class Person3: Person2 {
  convenience init() {
    self.init(
      name: "Terrance Phillip",
      age: 42
    )
  }
}

В качестве руководства используйте 1. параметры по умолчанию и 2. удобные инициализаторы, когда это возможно. (И в качестве расширения 2 преобразуйте обозначенные инициализаторы в вспомогательные в подклассах.) Вам придется поддерживать меньше кода.

...