DasterFlutter

O que são mixins e qual sua importância no Dart

O que são mixins e qual sua importância no Dart – Quando estamos desenvolvendo aplicações, é comum o uso de herança para evitar a reescrita de código. Basicamente, a herança é uma forma de uma classe obter atributos e métodos de outra classe, evitando a duplicidade e melhorando o reaproveitamento de código.

Porém, a herança por si só, não resolve todos os problemas. Imagine a seguinte situação:

Possuímos em nosso software, uma classe Pessoa , com seus atributos e métodos e três classes que herdam de Pessoa, as classes FuncionarioCliente e Fornecedor. Estas três classes são filhas de Pessoa e, por isso, herdam seus atributos e métodos:

Diagrama exemplificando uma herança

Porém, imagine que queremos adicionar um método que é comum a diversas classes que herdam de Pessoa, mas nem todas. A primeira opção seria desenvolver estes métodos apenas nas classes que iriam utilizá-las, porém, desta forma, há a duplicidade de código, já que mais de uma classe irá utilizar o mesmo método.

A segunda opção seria utilizar um recurso presente no Dart chamado de Mixins, como veremos abaixo.

O que são Mixins e como eles funcionam?

Basicamente, os Mixins são recursos presentes no Dart que nos permitem adicionar um conjunto de “características” a uma classe sem a necessidade de utilizar uma herança.

Voltando ao exemplo anterior, imagine as classes abaixo:

abstract class Pessoa {
  String _nome;
  int _idade;
  String _sexo;
  String _email;

  Pessoa(String nome, int idade, String sexo, String email) {
    this._nome = nome;
    this._idade = idade;
    this._sexo = sexo;
    this._email = email;
  }

// getters e setters
// métodos
}

class Funcionario extends Pessoa {
  String _cargo;

  Funcionario(String nome, int idade, String sexo, String email, String cargo)
      : this._cargo = cargo,
        super(nome, idade, sexo, email);

// getters e setters
// métodos
}

Copiar

class Cliente extends Pessoa {
  bool _ativo;

  Cliente(String nome, int idade, String sexo, String email, bool ativo)
      : this._ativo = ativo,
        super(nome, idade, sexo, email);

// getters e setters
// métodos
}

Copiar

class Fornecedor extends Pessoa {
  String _empresa;

  Fornecedor(String nome, int idade, String sexo, String email, String empresa)
      : this._empresa = empresa,
        super(nome, idade, sexo, email);

// getters e setters
// métodos
}

Agora precisamos implementar o método abastecer() que servirá para um funcionário ou fornecedor abastecer a prateleira de um supermercado. Onde seria o melhor local para isso? Se implementarmos na classe Pessoa, o Cliente também conseguirá acesso a este método, o que não é correto para o que queremos. E é aí que entram os Mixins \o

Com o uso dos Mixins, podemos desenvolver o método abastecer() de forma “isolada” e apenas permitir que determinadas classes possuam acesso a ele. Para isso, criamos o Mixin da seguinte forma:

mixin Abastecer {
  void abastecer() {
    print("Prateleira abstecida");
  }
}

Por ser uma classe especial, os mixins não precisam de construtores.

Agora, para definirmos as classes que poderão utilizar o método abastecer(), utilizamos a palavra with, como podemos ver abaixo:Copiar

class Funcionario extends Pessoa with Abastecer{
  String _cargo;

  Funcionario(String nome, int idade, String sexo, String email, String cargo)
      : this._cargo = cargo,
        super(nome, idade, sexo, email);

// getters e setters
// métodos
}

class Fornecedor extends Pessoa with Abastecer{
  String _empresa;

  Fornecedor(String nome, int idade, String sexo, String email, String empresa)
      : this._empresa = empresa,
        super(nome, idade, sexo, email);

// getters e setters
// métodos
}

Com isso, as classes Fornecedor e Funcionario poderão utilizar o método abastecer(), sem que a classe Cliente o faça:Copiar

main() {
cliente.abastecer(); //The method 'abastecer' isn't defined for the class 'Cliente'.
funcionario.abastecer(); //Prateleira abstecida
fornecedor.abastecer(); //Prateleira abstecida
}

Isso faz com que o reaproveitamento do nosso código seja ainda mais eficiente, já que o método abastecer() só será implementado uma vez, mas poderá ser utilizado quantas vezes forem necessárias. Outras linguagens possuem recursos parecidos com os mixins no Dart, como o PHP e as Traits.