O que é um construtor
O construtor é uma função especial usada para criar instâncias de classe, geralmente responsável por inicializar propriedades. Com exceção do construtor padrão, todos os construtores têm o mesmo nome da classe.
Classificação dos construtores no Dart:
- Construtor Generativo (Generative)
- Construtor Padrão (Default)
- Construtor Nomeado (Named)
- Construtor Constante (Const)
- Construtor Redirecionador (Redirecting)
- Construtor de Fábrica (Factory)
- Construtor de Fábrica Redirecionador
- Sintaxe Concisa de Construtor (Dart 3.13+)
- Construtor Primário (Primary Constructors, sintaxe compacta de campos + construtor)
1. Construtor Generativo Generative Constructor
O construtor mais básico, cria instâncias e inicializa variáveis de membro. Suporta parâmetros inicializadores this.variavel para simplificar atribuição.
class Point {
double x;
double y;
// Construtor generativo, this.x recebe o parâmetro diretamente para atribuir ao membro
Point(this.x, this.y); // Atribui valores diretamente para x e y
}
void main() {
final p = Point(10, 20);
print("(${p.x}, ${p.y})"); // (10, 20)
}
Code language: JavaScript (javascript)
2. Construtor Padrão Default Constructor
Se a classe não tiver nenhum construtor definido manualmente, o Dart fornece automaticamente um construtor generativo sem parâmetros e sem nome. Esse comportamento é igual a outras linguagens baseadas em C como C++, Java, C# e outras.
class PointA {
double x = 0;
double y = 0;
// Construtor padrão implícito: PointA();
}
void main() {
final p = PointA(); // Chama automaticamente o construtor padrão
print("(${p.x}, ${p.y})"); // (0.0, 0.0)
}
Code language: PHP (php)
Aviso: Ao escrever qualquer construtor manualmente, o construtor padrão desaparece.
3. Construtor Nomeado Named Constructor
Objetivo: Definir vários construtores em uma única classe com semântica clara; formato NomeClasse.NomeConstrutor()
const double xOrigin = 0;
const double yOrigin = 0;
class Point {
final double x;
final double y;
// Construtor generativo principal
Point(this.x, this.y);
// Construtor nomeado: ponto de origem
Point.origin() : x = xOrigin, y = yOrigin;
}
void main() {
final p1 = Point(5, 6);
final p2 = Point.origin(); // Chamar construtor nomeado
print(p1.x); //5
print("Ponto de origem: (${p2.x}, ${p2.y})"); // (0,0)
}
Code language: PHP (php)
Regras Importantes
- Subclasses não herdam os construtores nomeados da classe pai; se precisar de um construtor nomeado igual na subclasse, deve implementá-lo manualmente;
- Construtores nomeados suportam lista de inicialização para atribuir valores a variáveis final.
4. Construtor Constante Const Constructor
Usado para criar objetos constantes em tempo de compilação, requisitos:
- Todas as variáveis de membro devem ser marcadas com
final - Adicione a palavra-chave
constno construtor; ao instanciar comconst, o cache de constantes é reutilizado. Sem o const, uma instância nova comum é criada.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0); // Estático pertencente à classe, compartilhado por toda a classe
final double x, y;
// O construtor constante pode inicializar x e y declarados como final
const ImmutablePoint(this.x, this.y);
}
void main() {
// Constante de compilação, reutiliza o mesmo objeto
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2); // Apenas parâmetros idênticos compartilham a mesma instância
print(p1 == p2); // true
// Instância comum, objeto novo separado
final p3 = ImmutablePoint(1, 2);
print(p1 == p3); // false
}Code language: PHP (php)
5. Construtor Redirecionador Redirecting Constructor
Construtor que encaminha a execução para outro construtor da mesma classe com a sintaxe : this(parâmetros), o corpo da função deve estar vazio.
class Point {
double x, y;
// Construtor principal
Point(this.x, this.y);
// Construtor redirecionador: recebe apenas x, y fixado em 0, encaminha para o construtor principal
Point.alongX(double x) : this(x, 0); // Chama o construtor nomeado, envia x para o construtor principal e fixa y=0
}
void main() {
final p = Point.alongX(9);
print("x=${p.x}, y=${p.y}"); // x=9, y=0
}
Code language: JavaScript (javascript)
6. Construtor de Fábrica Factory Constructor
Palavra-chave factory, cenários de uso:
- Nem sempre cria um objeto novo (reutilização de cache, retorno de instâncias de subclasse)
- Lógica complexa antes da criação do objeto (parse de JSON, validação de parâmetros). Restrição: não pode acessar
this
Exemplo de Logger Singleton com Cache
class Logger {
final String name;
bool mute = false;
// Cache privado visível apenas dentro da biblioteca
static final Map<String, Logger> _cache = {};
// Construtor de fábrica: busca primeiro no cache
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
// Construtor de fábrica: cria a partir de parse json
factory Logger.fromJson(Map<String, dynamic> json) {
return Logger(json["name"].toString());
}
// Construtor generativo interno privado
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
final log1 = Logger("UI");
final log2 = Logger("UI");
print(log1 == log2); // true, mesmo objeto do cache
final jsonLog = Logger.fromJson({"name": "Net"});
jsonLog.log("request success");
}
Code language: JavaScript (javascript)
7. Construtor de Fábrica Redirecionador Redirecting Factory
Sintaxe factory Nome() = ConstrutorOutraClasse;, ideal para classes abstratas que delegam a criação de instâncias e evitam repetição de definição de parâmetros.
abstract class Listenable {}
class _MergingListenable implements Listenable {
List<_MergingListenable> list;
_MergingListenable(this.list);
}
// Fábrica redirecionadora, chama o construtor da classe privada interna
factory Listenable.merge(List<Listenable> list) = _MergingListenable;
Code language: PHP (php)
8. Constructor Tear-offs (Desacoplamento de Construtores)
Passe o construtor diretamente como argumento de função sem escrever (), substitui lambdas anônimas redundantes com melhor performance.
Forma Recomendada
void main() {
final charCodes = [65, 66, 67];
// Construtor nomeado String.fromCharCode
final strs = charCodes.map(String.fromCharCode);
print(strs); // (A, B, C)
// Desacoplamento de construtor sem nome com .new
final buffers = charCodes.map(StringBuffer.new);
}
Code language: PHP (php)
Não Recomendado: Lambda Excessivo
// Empacotamento desnecessário, evite essa forma
charCodes.map((code) => String.fromCharCode(code));
Code language: JavaScript (javascript)
9. Sintaxe Concisa de Construtor (Dart 3.13+) Concise Constructor
Dentro da classe é possível omitir o nome da classe, usar diretamente new / factory para definir construtores sem escrever NomeClasse.xxx:
| Sintaxe Tradicional | Abreviação |
|---|---|
Point(this.x,this.y) | new(this.x,this.y) |
Point.origin():x=0,y=0 | new origin():x=0,y=0 |
factory Point.clone() | factory clone() |
class Point {
double x, y;
// Abreviação de construtor generativo sem nome
new(this.x, this.y);
// Abreviação de construtor generativo nomeado
new origin() : x = 0, y = 0;
// Abreviação de construtor de fábrica
factory clone(Point other) => new(other.x, other.y);
}
void main() {
final p = new(3, 4);
final origin = new origin();
final copy = p.clone(p);
}
Code language: PHP (php)
10. Três Formas de Inicializar Variáveis de Instância
1: Atribuição direta na declaração
class PointA {
double x = 1.0;
double y = 2.0;
}
Code language: JavaScript (javascript)
2: Parâmetros Inicializadores
this.variavel
Suporta parâmetros posicionais opcionais, parâmetros nomeados e variáveis nullable
class PointB {
final double x;
final double y;
// Parâmetros posicionais opcionais
PointB.opt([this.x = 0, this.y = 0]);
// Parâmetros nomeados com valor padrão
PointB.named({this.x = 5, this.y = 5});
}
Code language: JavaScript (javascript)
3: Lista de Inicialização Initializer List
Atribuição após dois pontos :, executado antes do corpo do construtor, não pode acessar this, suporta assert para validação de parâmetros.
class Point {
final double x;
final double y;
Point.fromJson(Map<String, double> json)
: x = json["x"]!,
y = json["y"]! {
print("Corpo do construtor executado, x=$x");
}
// Com validação por assert
Point.withAssert(this.x, this.y) : assert(x >= 0);
}
Code language: JavaScript (javascript)
11. Parâmetros Inicializadores Diretos para Campos Privados (Dart3.12+)
Para variáveis privadas com prefixo sublinhado, escreva os parâmetros do construtor como this._campo; ao chamar externamente use diretamente o nome público sem sublinhado.
class Point {
final double _x;
final double _y;
// Interno usa _x, chamada externa escreve x:10
Point({required this._x, this._y = 0});
}
void main() {
final p = Point(x: 10); // Não precisa escrever _x, apenas x
print(p._x); // 10
}
Code language: PHP (php)
Use o nome original da variável privada dentro da lista de inicialização:
class Point {
final double _x;
Point({required this._x}) : assert(_x > 0);
}
Code language: JavaScript (javascript)
12. Construtores da Classe Pai e Regras de Herança
- Subclasses não herdam nenhum construtor da classe pai;
- Ordem de execução do construtor: lista de inicialização → construtor da classe pai → corpo do construtor da subclasse;
- Se a classe pai não tiver construtor padrão sem parâmetros, a subclasse deve chamar manualmente
super()para especificar o construtor da classe pai.
Exemplo Básico de Chamada super
Assim como no Java, usamos super para se referir à classe base; no C# se usa base.
class Person {
final String name;
Person(this.name);
Person.fromMap(Map map) : name = map["name"];
}
class Employee extends Person {
int id;
// Chamar construtor nomeado da classe pai
Employee(Map data) : super.fromMap(data), id = data["id"];
}
Code language: JavaScript (javascript)
Aviso: Nas expressões de parâmetros do super não é permitido usar
this.
Parâmetros Super (Dart2.17+, simplifica envio de parâmetros para a classe pai)
Use super.variavel para encaminhar parâmetros diretamente ao construtor da classe pai sem escrever manualmente super(x,y)
class Vector2d {
final double x, y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// super.x super.y são encaminhados automaticamente para o construtor pai
Vector3d(super.x, super.y, this.z);
}
// Construtor nomeado da classe pai + parâmetros nomeados super
class Vector3dYZ extends Vector2d {
final double z;
Vector3dYZ({required super.y, required this.z}) : super.named(x: 0);
}
Code language: JavaScript (javascript)