Posterior a de esta larga compilación de datos solucionamos esta impedimento que tienen ciertos de nuestros usuarios. Te regalamos la respuesta y nuestro objetivo es serte de mucha apoyo.
Solución:
tl; dr Utilice una fábrica en situaciones en las que no necesariamente quiero devolver un nuevo instancia de la propia clase. Casos de uso:
- el constructor es caro, por lo que desea devolver una instancia existente, si es posible, en lugar de crear una nueva;
- solo desea crear una instancia de una clase (el patrón singleton);
- desea devolver una instancia de subclase en lugar de la clase en sí.
Explicación
Una clase de dardos puede tener constructores generativos o constructores de fábricas. Un constructor generativo es una función que siempre devuelve una nueva instancia de la clase. Debido a esto, no utiliza el return
palabra clave. Un constructor generativo común tiene la forma:
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
Un constructor de fábricas tiene restricciones más flexibles que un constructor generativo. La fábrica solo necesita devolver una instancia que sea del mismo tipo que la clase o que implemente sus métodos (es decir, satisfaga su interfaz). Esta podría ser una nueva instancia de la clase, pero también podría ser una instancia existente de la clase o una instancia nueva / existente de una subclase (que necesariamente tendrá los mismos métodos que el padre). Una fábrica puede utilizar el flujo de control para determinar qué objeto devolver y debe utilizar el return
palabra clave. Para que una fábrica devuelva una nueva instancia de clase, primero debe llamar a un constructor generativo.
En su ejemplo, el constructor de fábrica sin nombre primero lee de una propiedad Map llamada _cache
(que, porque es Static
, se almacena a nivel de clase y, por lo tanto, es independiente de cualquier variable de instancia). Si ya existe una variable de instancia, se devuelve. De lo contrario, se genera una nueva instancia llamando al constructor generativo nombrado Logger._internal
. Este valor se almacena en caché y luego se devuelve. Debido a que el constructor generativo toma solo un name
parámetro, el mute
la propiedad siempre se inicializará para false, pero se puede cambiar con el configurador predeterminado:
var log = Logger("...");
log.mute = true;
log.log(...); // will not print
El término factory
alude al Factory Pattern, que se trata de permitir que un constructor devuelva una instancia de subclase (en lugar de una instancia de clase) basándose en los argumentos proporcionados. Un buen ejemplo de este caso de uso en Dart es la clase de elemento HTML abstracto, que define docenas de funciones de constructor de fábrica con nombre que devuelven diferentes subclases. Por ejemplo, Element.div()
y Element.li()
regreso
elementos, respectivamente.
En esta aplicación de almacenamiento en caché, considero que “fábrica” es un nombre poco apropiado ya que su propósito es evitar llamadas al constructor generativo, y creo que las fábricas del mundo real son inherentemente generativas. Quizás un término más adecuado aquí sería “almacén”: si un artículo ya está disponible, sáquelo del estante y entréguelo. Si no es así, solicite uno nuevo.
¿Cómo se relaciona todo esto con los constructores nombrados? Los constructores generativos y de fábrica pueden ser sin nombre o con nombre:
...
// 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");
1) No hay mucha diferencia entre un static método y un constructor de fábrica.
Para un constructor de fábrica, el tipo de retorno se fija al tipo de la clase, mientras que para un static método, puede proporcionar su propio tipo de devolución.
Se puede invocar un constructor de fábrica con new
, pero eso se volvió casi irrelevante con opcional new
en Dart 2.
Hay otras características, como las redirecciones, que se utilizan con poca frecuencia y que son compatibles con los constructores (de fábrica), pero no con static métodos.
Probablemente sea una buena práctica utilizar un constructor de fábrica para crear instancias de clases en lugar de static métodos para hacer más obvio el propósito de la creación de objetos.
Esta es la razón por la que se usa un constructor de fábrica en el ejemplo que publicó y quizás porque el código se escribió originalmente en Dart 1, donde permitía crear una instancia de registrador con new
como con cualquier otra clase.
2) Sí, este es un constructor con nombre y el prefix _
lo convierte en un constructor con nombre privado. Solo los constructores con nombre se pueden convertir en privados porque de lo contrario no habría lugar para agregar el _
prefix.
Se utiliza para evitar la creación de instancias desde cualquier otro lugar que no sea el constructor de la fábrica pública. De esta forma se asegura que no puede haber más de una Logger
instancia en su aplicación. El constructor de fábrica solo crea una instancia la primera vez y, para las llamadas posteriores, siempre devuelve la instancia creada anteriormente.
Complementando la respuesta de Dave, este código muestra un ejemplo claro cuando se usa la fábrica para devolver una clase relacionada con los padres.
Eche un vistazo a este código de https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3
Puede ejecutar este código aquí. https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef
Realice algunos cambios para aprender cómo funcionaría en determinadas situaciones, como singletons.
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);
valoraciones y comentarios
Si conservas algún titubeo y capacidad de innovar nuestro sección te inspiramos ejecutar una anotación y con deseo lo observaremos.