Mixin vs Herança
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy. Lição 54 de 110.
Agora que você aprendeu como os mixins funcionam, vamos esclarecer quando usá-los em vez de herança. A principal diferença reside na relação que eles expressam.
Herança representa uma relação "é-um". Um Dog é um Animal. A subclasse é uma versão especializada da classe pai, e você só pode estender uma única classe.
Mixins, por outro lado, representam uma relação "pode-fazer". Um Dog pode nadar, mas nadar não é o que define um cachorro.
// Herança: Dog É um Animal
class Animal {
String name;
Animal(this.name);
}
class Dog extends Animal {
Dog(String name) : super(name);
}
// Mixin: Dog PODE nadar (mas não é definido pelo ato de nadar)
mixin Swimming {
void swim() => print('Swimming');
}
class Dog extends Animal with Swimming {
Dog(String name) : super(name);
}Use herança quando as classes compartilham uma identidade fundamental e você precisa de construtores na classe pai. Use mixins quando quiser adicionar funcionalidades a classes que não compartilham um ancestral comum.
| Recurso | Herança | Mixin |
|---|---|---|
| Relacionamento | is-a | can-do |
| Limite | Apenas um pai | Vários mixins |
| Construtores | Permitidos | Não permitidos |
| Caso de uso | Especialização | Comportamento compartilhado |
A melhor parte? Você pode combinar ambos - estender uma classe e incorporar múltiplas capacidades, dando às suas classes exatamente os recursos de que precisam.
Desafio
FácilVamos criar um sistema de trabalhadores que demonstra quando usar herança em vez de mixins. Você criará uma classe base para o relacionamento "é um" e mixins para capacidades de "pode fazer", combinando-os para mostrar como as duas abordagens funcionam juntas.
Você organizará seu código em três arquivos:
worker.dart: Defina sua classe base, que estabelece a identidade principal de todos os trabalhadores:- Uma classe
Workercom as propriedadesString nameeString department. Inclua um construtor que receba os dois valores. Adicione um métodointroduce()que imprime[name] works in [department]
- Uma classe
skills.dart: Defina mixins que representem capacidades que os trabalhadores podem ter (os relacionamentos de "pode fazer"):- Um mixin
CanCodecom um métodowriteCode()que imprimeWriting code... - Um mixin
CanDesigncom um métodocreateDesign()que imprimeCreating design... - Um mixin
CanManagecom um métodoleadTeam()que imprimeLeading the team...
- Um mixin
main.dart: Importe os dois arquivos e crie tipos especializados de trabalhadores que combinem herança com mixins:- Uma classe
Developerque estendeWorkere usa o mixinCanCode - Uma classe
TechLeadque estendeWorkere usa os mixinsCanCodeeCanManage - Crie um
Developerchamado'Alice'no departamento'Engineering' - Crie um
TechLeadchamado'Bob'no departamento'Engineering' - Para Alice: chame
introduce()e depoiswriteCode() - Imprima uma linha vazia
- Para Bob: chame
introduce(), depoiswriteCode()e entãoleadTeam()
- Uma classe
Observe como tanto Developer quanto TechLead são trabalhadores (herança), mas podem fazer coisas diferentes (mixins). TechLead combina várias capacidades sem precisar de herança múltipla.
Saída esperada:
Alice works in Engineering
Writing code...
Bob works in Engineering
Writing code...
Leading the team...Experimente você mesmo
import 'worker.dart';
import 'skills.dart';
// TODO: Crie uma classe Developer que estende Worker e usa o mixin CanCode
// TODO: Crie uma classe TechLead que estende Worker e usa ambos os mixins CanCode e CanManage
void main() {
// TODO: Crie um Developer chamado 'Alice' no departamento 'Engineering'
// TODO: Chame introduce() e depois writeCode() para Alice
// TODO: Imprima uma linha vazia
// TODO: Crie um TechLead chamado 'Bob' no departamento 'Engineering'
// TODO: Chame introduce(), writeCode() e depois leadTeam() para Bob
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos externosBibliotecas e importsIntrodução à OOPClasses vs. objetosA palavra-chave thisMétodosVariáveis de instânciaNoções básicas de construtoresRevisão - Calculadora simples4Segurança contra nulos
Introdução à segurança contra nulosAnulável vs. não anulávelOs operadores ? e !Palavra-chave Late e segurança contra nulosOperadores conscientes de nulosSegurança contra nulos em classesRecapitulação — Sistema de perfil de usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementação vs. ExtensãoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Genéricos
Visão geral de List, Set e MapColeções com segurança de tiposClasses genéricasMétodos genéricosRestrições genéricasIterable e IteratorRecapitulação - Armazenamento genérico13Conceitos Avançados de OOP
Composição vs. HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Registros (Dart 3)Padrões e Correspondência (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários2Construtores em Dart
Construtor padrãoConstrutores nomeadosListas de inicializaçãoConstrutores constantesConstrutores factoryConstrutores de redirecionamentoRevisão - Construtor de formas5Encapsulamento
Membros Públicos vs. PrivadosConvenção do Prefixo _Privacidade no Nível da BibliotecaAprofundamento em Getters e SettersOcultação de InformaçõesRecapitulação - Registros de Alunos8Mixins
Introdução a MixinsCriando MixinsUsando vários MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema de Animais11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode e ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs. EstáticosCampos Final e ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Contas Bancárias6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodosA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do polimorfismoPolimorfismo por meio de interfacesVerificação de tipos em tempo de execuçãoOs operadores is e asPalavra-chave covarianteRecapitulação — Processador de pagamentos12OOP Assíncrona
Futures e async/awaitNoções básicas de StreamsControladores de StreamConstrutores assíncronosAsync em métodos de classeRecapitulação — Buscador de dados15Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão RepositoryPratique por conta própria: Compilador de Dart online