Понимание примера кода конструктора Factory - Dart - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть несколько острых вопросов о примере конструкторов фабрики, упомянутом здесь (https://www.dartlang.org/guides/language/language-tour#factory-constructors). Мне известны только три типа конструкторов на базовом уровне - по умолчанию, с именами и параметризацией.

  1. Почему я должен использовать factory вообще для этого примера?
  2. Это именованный конструктор, который используется? И почему? Example factory constructor

Ответы [ 3 ]

0 голосов
/ 13 мая 2019

tl; dr Используйте фабрику в ситуациях, когда вы не обязательно хотите вернуть новый экземпляр самого класса.Варианты использования:

  • конструктор дорогой, поэтому вы хотите вернуть существующий экземпляр - если это возможно - вместо создания нового;
  • вы когда-нибудь захотите создать только один экземпляр класса (шаблон синглтона);
  • вы хотите вернуть экземпляр подкласса вместо самого класса.

Объяснение

Класс Dart может иметь генеративные конструкторы или фабричные конструкторы. Генеративный конструктор - это функция, которая всегда возвращает новый экземпляркласс.Из-за этого он не использует ключевое слово return.Обычный порождающий конструктор имеет форму:

class Person {
  String name;
  String country;

  // unnamed generative constructor
  Person(this.name, this.country);
}
var p = Person("...") // returns a new instance of the Person class

У фабричного конструктора более слабые ограничения, чем у порождающего конструктора.Фабрике нужно только возвращать экземпляр того же типа, что и класс, или реализующий его методы (т.е. удовлетворяющий его интерфейсу).Этот может быть новым экземпляром класса, но также может быть существующим экземпляром класса или новым / существующим экземпляром подкласса (который обязательно будет иметь те же методы, что и родительский).Фабрика может использовать поток управления для определения объекта, который нужно вернуть, и должна использовать ключевое слово return.Чтобы фабрика возвращала новый экземпляр класса, она должна сначала вызвать производительный конструктор.

Dart Factory Explained

В вашем примере, неназванный конструктор фабрики сначала читает свойство Map с именем _cache (которое, поскольку оно Static, являетсяхранится на уровне класса и, следовательно, не зависит от какой-либо переменной экземпляра).Если переменная экземпляра уже существует, она возвращается.В противном случае новый экземпляр генерируется путем вызова именованного производительного конструктора Logger._internal.Это значение кэшируется и затем возвращается.Поскольку генеративный конструктор принимает только параметр name, свойство mute всегда будет инициализировано как false, но его можно изменить с помощью установщика по умолчанию:

var log = Logger("...");
log.mute = true;
log.log(...); // will not print

Термин factory ссылается наФабричный шаблон, который позволяет конструктору возвращать экземпляр подкласса (вместо экземпляра класса) на основе предоставленных аргументов.Хорошим примером этого варианта использования в Dart является абстрактный HTML элементный класс , который определяет десятки именованных функций конструктора фабрики, возвращающих разные подклассы.Например, Element.div() и Element.li() возвращают элементы <div> и <li> соответственно.

В этом приложении для кэширования я считаю "фабрику" немного неправильной, поскольку ее цель - избежать вызововк генеративному конструктору, и я думаю о фабриках реального мира как по сути порождающих.Возможно, более подходящим термином здесь будет «склад»: если предмет уже есть в наличии, достаньте его с полки и доставьте.Если нет, позвоните для нового.

Как все это относится к именованным конструкторам?Генераторные и фабричные конструкторы могут быть либо безымянными, либо именованными:

...
  // named generative
  // delegates to the default generative constructor
  Person.greek(String name) : this(name, "Greece"); 

  // named factory 
  factory Person.greek(String name) {
    return Greek(name);
  }
}

class Greek extends Person {
  Greek(String name) : super(name, "Greece");
}


0 голосов
/ 12 июня 2019

В дополнение к ответу Дейва этот код демонстрирует ясный пример использования фабрики для возврата родительского связанного класса.

Посмотрите этот код из https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3

Вы можете запустить этот код здесь.https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef

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

import 'dart:math';

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(2);
    if (type == 'square') return Square(2);
    // To trigger exception, don't implement a check for 'triangle'.
    throw 'Can\'t create $type.';
  }
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

class Triangle implements Shape {
  final num side;
  Triangle(this.side);
  num get area => pow(side, 2) / 2;
}

main() {
  try {
    print(Shape('circle').area);
    print(Shape('square').area);
    print(Shape('triangle').area);
  } catch (err) {
    print(err);
  }
}
0 голосов
/ 21 декабря 2018

1) Между статическим методом и конструктором фабрики нет большой разницы.

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

Конструктор фабрики можно вызывать с помощью new, но это стало по большей части неактуальным с необязательным new в Dart 2.

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

Вероятно, все еще хорошей практикой является использование конструктора фабрики для создания экземпляров классов вместо статических методов, чтобы сделать цель создания объекта более очевидной.

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

2) Да, это именованный конструктор, а префикс _ делает его закрытым именованным конструктором.Только именованные конструкторы могут быть сделаны закрытыми, потому что в противном случае не было бы места для добавления префикса _.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...