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
.Чтобы фабрика возвращала новый экземпляр класса, она должна сначала вызвать производительный конструктор.
В вашем примере, неназванный конструктор фабрики сначала читает свойство 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");
}