Именованный конструктор Dart, статический метод и конструктор фабрики

Учитывая следующий код:

const jsonString = '{"myString":"Hello"}';
final jsonMap = jsonDecode(jsonString);

final myObject = MyClass.fromJson(jsonMap);

Сколько существует способов создать новый объект с использованием этого синтаксиса:

MyClass.fromJson(jsonMap)

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


person Suragch    schedule 07.08.2020    source источник


Ответы (2)


Чтобы создать новый экземпляр объекта, используйте следующий синтаксис:

MyClass.fromJson(jsonMap)

Для использования со следующим кодом:

// import 'dart:convert';

const jsonString = '{"myString":"Hello"}';
final jsonMap = jsonDecode(jsonString);

final myObject = MyClass.fromJson(jsonMap);

Есть как минимум следующие способы сделать это (с дополнительными примечаниями о характеристиках каждого из них):

Генеративный конструктор

class MyClass {
  MyClass(this.myString);
  final String myString;

  MyClass.fromJson(Map<String, dynamic> json) : this(json['myString']);
}

Есть два типа генеративных конструкторов: именованные и безымянные. MyClass.fromJson() - это именованный конструктор, а MyClass() - безымянный конструктор. К генеративным конструкторам применяются следующие принципы:

  • Генеративные конструкторы могут создавать только сам класс.
  • Генеративные конструкторы могут использовать список инициализаторов.
  • Генеративные конструкторы могут использовать только параметры инициализации или список инициализаторов для установки свойств final, то есть не в теле конструктора.
  • Генеративные конструкторы могут быть const, даже если они не перенаправляют.

Конструктор фабрики

class MyClass {
  MyClass(this.myString);
  final String myString;

  factory MyClass.fromJson(Map<String, dynamic> json) {
    return MyClass(json['myString']);
  }
}
  • Конструкторы фабрики могут возвращать подтип класса.
  • Конструкторы фабрики можно использовать для создания синглтонов.
  • Конструкторы фабрик могут быть безымянными, как генеративные конструкторы.
  • Конструкторы фабрики могут быть const, но только при перенаправлении.

Статический метод

class MyClass {
  MyClass(this.myString);
  final String myString;

  static MyClass fromJson(Map<String, dynamic> json) {
    return MyClass(json['myString']);
  }
}
  • Статические методы могут возвращать что угодно, в том числе Future.
  • Статические методы можно использовать для создания синглтонов.
  • Статические методы можно использовать как отрывные.

дальнейшее чтение

person Suragch    schedule 07.08.2020
comment
Что вы имеете в виду под Named constructors may only use the initializer list to set final properties.? даже с именованными конструкторами, такими как MyClass.named(this.myString), вы можете инициализировать окончательные свойства. Также вы можете создавать синглтоны с помощью factory конструктора, например здесь - person Mattia; 07.08.2020
comment
@Mattia, спасибо, что указали на это. Я имел в виду, что окончательные свойства не могут быть установлены в теле именованного конструктора, но я не был достаточно конкретным. Я обновил свой ответ на этот вопрос. Что касается синглтонов, я уже упоминал об этом. (Однако, если использовать статические методы, может показаться, что это единственный способ создать синглтон. Это правда?) - person Suragch; 07.08.2020
comment
@lrn У меня создалось впечатление, что генеративные конструкторы - это конструкторы без имен, то есть те, которые просто используют имена классов. Это не правда? - person Suragch; 08.08.2020
comment
@lrn Я задал свой вопрос более подробно здесь: stackoverflow.com/questions/63313102/ - person Suragch; 08.08.2020
comment
Ответили там, но нет, это неправда. Генеративность или фабрика ортогональна названию или нет. Конструкторы фабрики - это конструкторы с префиксом factory, остальные являются генеративными. Любой из них может быть назван или безымянным. - person lrn; 09.08.2020

Помимо подробного ответа @suragch. Я хотел бы выделить несколько пунктов, которые показывают, что factory constructor - лучший вариант для описанного выше сценария (для метода fromJson ()).

  • При использовании конструкторов фабрики вам не нужно инициализировать переменные экземпляра этого класса. (но при использовании генеративных конструкторов необходимо инициализировать все конечные переменные экземпляра)

  • Конструктор фабрики может возвращать существующий объект. Например: - при использовании пакета json_seriazible метод fromJson () возвращает существующий (ранее созданный) объект. Таким образом, с этим пакетом мы можем использовать только фабричные конструкторы.

  • Конструкторы фабрики могут возвращать любой подтип этого класса, но при использовании генеративных конструкторов он может возвращать только объект точного типа этого класса.

  • Гарантирует, что когда-либо создается только один экземпляр класса (шаблон singleton). (объект стоит дорого, поэтому для fromJson необходим шаблон singleton)

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

person TDM    schedule 21.04.2021
comment
Что касается вашего пункта 4, я бы квалифицировал это, сказав, что его можно использовать для создания синглтона. Однако конструктор фабрики также можно использовать для создания каждый раз нового объекта. - person Suragch; 21.04.2021
comment
@Suragch [Если конструктор фабрики возвращает существующий объект = ›шаблон синглтона True (точка 4 верна.)] [Но если конструктор фабрики возвращает вызов конструктора (создать новый экземпляр) =› шаблон синглтона False (точка 4 неверна.) I думаю, это то, что вы пытаетесь сказать. Я прав? - person TDM; 21.04.2021
comment
Да, это правильно. - person Suragch; 22.04.2021