construtor

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:

  1. Construtor Generativo (Generative)
  2. Construtor Padrão (Default)
  3. Construtor Nomeado (Named)
  4. Construtor Constante (Const)
  5. Construtor Redirecionador (Redirecting)
  6. Construtor de Fábrica (Factory)
  7. Construtor de Fábrica Redirecionador
  8. Sintaxe Concisa de Construtor (Dart 3.13+)
  9. 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:

  1. Todas as variáveis de membro devem ser marcadas com final
  2. Adicione a palavra-chave const no construtor; ao instanciar com const, 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:

  1. Nem sempre cria um objeto novo (reutilização de cache, retorno de instâncias de subclasse)
  2. 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 TradicionalAbreviação
Point(this.x,this.y)new(this.x,this.y)
Point.origin():x=0,y=0new 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

  1. Subclasses não herdam nenhum construtor da classe pai;
  2. Ordem de execução do construtor: lista de inicialização → construtor da classe pai → corpo do construtor da subclasse;
  3. 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)

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *