diegoRodicio

View Categories

🧬 Herdanza, super e clases abstractas

Tempo de lectura estimado: 3 minutos

A herdanza permite crear unha clase a partir doutra. Usamos extends: a clase orixinal é a superclase e a nova é a subclase.

Un profesor é unha persoa. Pode herdar datos e métodos de Persoa e engadir outros propios.

🧬 extends e a chamada ao construtor con super

class Persoa {
  final String nome;
  Persoa(this.nome);

  void saudar() {
    print('Ola, son $nome.');
  }
}

class Profesor extends Persoa {
  // A superclase necesita un nome: pasámosllo con super(nome).
  Profesor(String nome) : super(nome);

  void explicar() {
    print('$nome explica Dart.'); // nome é un atributo herdado
  }
}

void main() {
  var profesor = Profesor('Diego Rodicio');
  profesor.saudar(); // Método herdado
  profesor.explicar(); // Método propio
}

Os construtores non se herdan. Se non escribimos unha chamada ao da superclase, Dart intenta chamar a super() sen argumentos. Se ese construtor necesita datos, debemos pasalos.

✂️ A forma curta: parámetros super

Podemos evitar repetir un parámetro que só se pasa á superclase. Por exemplo, Profesor(String nome) : super(nome); pode escribirse Profesor(super.nome);.

Tamén funciona cos parámetros nomeados:

class Persoa {
  final String nome;
  Persoa({required this.nome});
}

class Profesor extends Persoa {
  // Recibe nome e pásallo ao construtor de Persoa.
  Profesor({required super.nome});
}

void main() {
  var profesor = Profesor(nome: 'Diego Rodicio');
  print(profesor.nome);
}

📱 Esta é a idea que hai detrás de super.key en Flutter: recibir un parámetro e pasalo ao construtor da superclase. O significado de key verémolo en Flutter.

🔁 Sobrescribir un método e usar super.metodo()

Sobrescribir é dar a nosa propia versión dun método herdado. Engadimos @override para indicar a intención; o analizador avísanos se non existe un membro que sobrescribir.

Se queremos conservar o comportamento anterior e engadir algo, podemos chamar a super.metodo(). Non é obrigatorio en todos os métodos: depende do que queiramos facer e do contrato da superclase.

🧪 Exemplo completo: ampliar un saúdo

🔗 Ver o código en DartPad — https://dartpad.dev/?id=ece7d59f9e194522395fca282ea9e74a

En Flutter tamén sobrescribiremos métodos e atoparemos chamadas como super.initState() e super.dispose(). Alí veremos cando se executan e a orde que debemos respectar.

🧩 Clases e métodos abstractos

Unha clase abstract serve de base e non se pode instanciar directamente. Pode deixar métodos sen corpo para que os completen as subclases concretas.

abstract class PersoaCentro {
  // Método abstracto: remata en ; porque aínda non ten implementación.
  void presentarse();
}

class Profesor extends PersoaCentro {
  @override
  void presentarse() {
    print('Son Diego Rodicio, profesor no IES San Mamede.');
  }
}

void main() {
  PersoaCentro persoa = Profesor();
  persoa.presentarse();
  // PersoaCentro(); // ❌ Non podemos instanciar a clase abstracta
}

Unha clase abstracta tamén pode ter atributos, construtores e métodos xa implementados. Verémolo no exemplo final.

🤝 implements: cumprir un contrato

Con extends herdamos implementación. Con implements comprometémonos a ofrecer os membros de instancia da interface, pero non herdamos o código que os implementa.

abstract class Presentable {
  void presentarse();
}

class Profesor implements Presentable {
  // Temos que proporcionar o método que esixe o contrato.
  @override
  void presentarse() {
    print('Son Diego Rodicio.');
  }
}

void main() {
  Presentable profesor = Profesor();
  profesor.presentarse();
}

Toda clase define unha interface, aínda que non leve a palabra interface. Aquí usamos unha clase abstracta para que o contrato sexa fácil de ver. Os construtores e membros estáticos non forman parte dese contrato.

🔎 Recordatorio: herdanza con tipos xenéricos

No Tema 2.1 vimos tipos como List<String>. As clases das que herdamos tamén poden recibir un tipo. En Flutter leremos extends State<MeuWidget>: é a clase State parametrizada co tipo MeuWidget. Non é outra forma distinta de herdanza.

🔗 Herdanza e sobrescritura — https://dart.dev/language/extend · Interfaces implícitas — https://dart.dev/language/classes#implicit-interfaces