Classes e Objetos
Definição de classes
Classes são modelos para criar objetos:
class Pessoa {
String nome;
int idade;
Pessoa(this.nome, this.idade);
void apresentar() {
print("Olá, meu nome é $nome e tenho $idade anos");
}
}
// Criar instância
var pessoa = Pessoa("João", 25);
pessoa.apresentar();
Members (propriedades e métodos)
class ListaDeTarefas {
// Propriedades
String usuario;
int quantidadeTarefas;
// Constructor
ListaDeTarefas(this.usuario, this.quantidadeTarefas);
// Métodos
void adicionarTarefa(int quantidade) {
quantidadeTarefas += quantidade;
}
void removerTarefa(int quantidade) {
if (quantidadeTarefas >= quantidade) {
quantidadeTarefas -= quantidade;
} else {
print("Quantidade insuficiente de tarefas");
}
}
int consultarQuantidade() {
return quantidadeTarefas;
}
}
Membros privados
Em Dart, membros privados são indicados com um underscore (_) no início do nome. Membros privados só podem ser acessados dentro da mesma biblioteca (arquivo).
class ListaDeTarefas {
String usuario; // Público - pode ser acessado de fora
int _quantidadeTarefas; // Privado - só acessível dentro desta classe/biblioteca
ListaDeTarefas(this.usuario, this._quantidadeTarefas);
// Método público
void adicionarTarefa(int quantidade) {
_quantidadeTarefas += quantidade; // Pode acessar _quantidadeTarefas dentro da classe
}
// Método privado
void _validarQuantidade(int quantidade) {
if (quantidade <= 0) {
throw ArgumentError("Quantidade deve ser positiva");
}
}
void removerTarefa(int quantidade) {
_validarQuantidade(quantidade); // Pode chamar método privado
if (_quantidadeTarefas >= quantidade) {
_quantidadeTarefas -= quantidade;
} else {
print("Quantidade insuficiente de tarefas");
}
}
// Getter público para acessar a quantidade
int get quantidadeTarefas => _quantidadeTarefas;
}
var lista = ListaDeTarefas("João", 10);
print(lista.usuario); // OK - membro público
// print(lista._quantidadeTarefas); // Erro! _quantidadeTarefas é privado
print(lista.quantidadeTarefas); // OK - usando o getter público
lista.adicionarTarefa(5);
// lista._validarQuantidade(3); // Erro! método privado
Importante:
- Membros sem
_são públicos e podem ser acessados de qualquer lugar - Membros com
_são privados e só podem ser acessados dentro do mesmo arquivo - Use membros privados para encapsular detalhes de implementação e proteger dados sensíveis
- Getters e setters públicos podem ser usados para controlar o acesso a membros privados
Constructors
Default constructor
class Pessoa {
String nome;
int idade;
Pessoa(this.nome, this.idade);
}
Named constructors
Construtores nomeados permitem diferentes formas de criar uma instância:
class Pessoa {
String nome;
int idade;
Pessoa(this.nome, this.idade);
Pessoa.recemNascido(String nome) : this(nome, 0);
Pessoa.anonima() : this("Anônimo", 0);
}
var bebe = Pessoa.recemNascido("Maria");
var anonimo = Pessoa.anonima();
Const constructors
Para objetos imutáveis:
class Ponto {
final int x;
final int y;
const Ponto(this.x, this.y);
}
const origem = Ponto(0, 0);
Getters e Setters
Getters e setters permitem controlar o acesso a propriedades:
class Retangulo {
double _largura;
double _altura;
Retangulo(this._largura, this._altura);
// Getter
double get area => _largura * _altura;
// Setter
set largura(double valor) {
if (valor > 0) {
_largura = valor;
}
}
double get largura => _largura;
double get altura => _altura;
}
var retangulo = Retangulo(5, 3);
print(retangulo.area); // 15
retangulo.largura = 10;
print(retangulo.area); // 30
Herança (extends)
Herança permite criar classes baseadas em outras classes:
class Animal {
String nome;
Animal(this.nome);
void fazerSom() {
print("Som genérico");
}
}
class Cachorro extends Animal {
Cachorro(String nome) : super(nome);
void fazerSom() {
print("Au au!");
}
void latir() {
print("$nome está latindo");
}
}
var cachorro = Cachorro("Rex");
cachorro.fazerSom(); // "Au au!"
cachorro.latir(); // "Rex está latindo"
Abstract classes
Classes abstratas não podem ser instanciadas diretamente:
abstract class Forma {
double calcularArea();
void desenhar() {
print("Desenhando forma");
}
}
class Circulo extends Forma {
double raio;
Circulo(this.raio);
double calcularArea() {
return 3.14159 * raio * raio;
}
}
// var forma = Forma(); // Erro! Não pode instanciar classe abstrata
var circulo = Circulo(5);
print(circulo.calcularArea()); // 78.54
Mixins
Mixins permitem reutilizar código em múltiplas hierarquias de classes:
mixin Nadador {
void nadar() {
print("Nadando...");
}
}
mixin Voador {
void voar() {
print("Voando...");
}
}
class Pato with Nadador, Voador {
String nome;
Pato(this.nome);
}
var pato = Pato("Donald");
pato.nadar(); // "Nadando..."
pato.voar(); // "Voando..."
Extension methods
Extensions permitem adicionar funcionalidades a classes existentes:
extension StringExtension on String {
String capitalize() {
if (isEmpty) return this;
return "${this[0].toUpperCase()}${substring(1)}";
}
bool isValidEmail() {
return contains('@') && contains('.');
}
}
String nome = "joão";
print(nome.capitalize()); // "João"
String email = "teste@email.com";
print(email.isValidEmail()); // true
Exercícios
-
Criação de classes: Crie uma classe
Bibliotecacom propriedadescodigo(String),quantidadeLivros(int) enome(String). Adicione métodosadicionarLivroeemprestarLivro. O métodoemprestarLivrodeve verificar se há livros disponíveis. -
Getters e Setters: Crie uma classe
Retangulocom propriedades privadas_largurae_altura. Crie getters para acessar os valores e setters que validem se os valores são positivos. Adicione um getterareaque calcule a área. -
Named constructors: Crie uma classe
Pessoacom propriedadesnomeeidade. Crie um constructor padrão e named constructors:Pessoa.recemNascido(idade 0) ePessoa.anonima(nome "Anônimo", idade 0). -
Herança: Crie uma classe abstrata
Animalcom método abstratofazerSom(). Crie classesCachorroeGatoque herdem deAnimale implementem o métodofazerSom(). -
Mixins: Crie mixins
NadadoreVoadorcom métodosnadar()evoar(). Crie uma classePatoque use ambos os mixins e demonstre o uso dos métodos.
Soluções
Ver solução do exercício 1
class Biblioteca {
String codigo;
int quantidadeLivros;
String nome;
Biblioteca(this.codigo, this.quantidadeLivros, this.nome);
void adicionarLivro(int quantidade) {
if (quantidade > 0) {
quantidadeLivros += quantidade;
print("$quantidade livro(s) adicionado(s). Total disponível: $quantidadeLivros");
} else {
print("Quantidade inválida");
}
}
void emprestarLivro(int quantidade) {
if (quantidade > 0) {
if (quantidadeLivros >= quantidade) {
quantidadeLivros -= quantidade;
print("$quantidade livro(s) emprestado(s). Livros restantes: $quantidadeLivros");
} else {
print("Livros insuficientes. Disponível: $quantidadeLivros");
}
} else {
print("Quantidade inválida");
}
}
void consultarDisponibilidade() {
print("Biblioteca $codigo ($nome): $quantidadeLivros livro(s) disponível(eis)");
}
}
void main() {
var biblioteca = Biblioteca("BIB-001", 100, "Biblioteca Central");
biblioteca.consultarDisponibilidade();
biblioteca.adicionarLivro(50);
biblioteca.emprestarLivro(30);
biblioteca.emprestarLivro(200); // Livros insuficientes
}
Ver solução do exercício 2
class Retangulo {
double _largura;
double _altura;
Retangulo(this._largura, this._altura);
double get largura => _largura;
double get altura => _altura;
set largura(double valor) {
if (valor > 0) {
_largura = valor;
} else {
print("Largura deve ser positiva");
}
}
set altura(double valor) {
if (valor > 0) {
_altura = valor;
} else {
print("Altura deve ser positiva");
}
}
double get area => _largura * _altura;
double get perimetro => 2 * (_largura + _altura);
}
void main() {
var retangulo = Retangulo(5.0, 3.0);
print("Área: ${retangulo.area}");
print("Perímetro: ${retangulo.perimetro}");
retangulo.largura = 10.0;
retangulo.altura = 4.0;
print("Nova área: ${retangulo.area}");
retangulo.largura = -5.0; // Erro: Largura deve ser positiva
}
Ver solução do exercício 3
class Pessoa {
String nome;
int idade;
Pessoa(this.nome, this.idade);
Pessoa.recemNascido(String nome) : this(nome, 0);
Pessoa.anonima() : this("Anônimo", 0);
void apresentar() {
print("Nome: $nome, Idade: $idade");
}
}
void main() {
var pessoa1 = Pessoa("João", 25);
pessoa1.apresentar();
var bebe = Pessoa.recemNascido("Maria");
bebe.apresentar();
var anonimo = Pessoa.anonima();
anonimo.apresentar();
}
Ver solução do exercício 4
abstract class Animal {
String nome;
Animal(this.nome);
void fazerSom();
void apresentar() {
print("Eu sou $nome");
}
}
class Cachorro extends Animal {
Cachorro(String nome) : super(nome);
void fazerSom() {
print("$nome faz: Au au!");
}
void latir() {
print("$nome está latindo");
}
}
class Gato extends Animal {
Gato(String nome) : super(nome);
void fazerSom() {
print("$nome faz: Miau!");
}
void miar() {
print("$nome está miando");
}
}
void main() {
var cachorro = Cachorro("Rex");
cachorro.apresentar();
cachorro.fazerSom();
cachorro.latir();
var gato = Gato("Mimi");
gato.apresentar();
gato.fazerSom();
gato.miar();
}
Ver solução do exercício 5
mixin Nadador {
void nadar() {
print("Estou nadando...");
}
}
mixin Voador {
void voar() {
print("Estou voando...");
}
}
class Pato with Nadador, Voador {
String nome;
Pato(this.nome);
void apresentar() {
print("Eu sou $nome, um pato");
}
}
class Peixe with Nadador {
String nome;
Peixe(this.nome);
void apresentar() {
print("Eu sou $nome, um peixe");
}
}
void main() {
var pato = Pato("Donald");
pato.apresentar();
pato.nadar();
pato.voar();
var peixe = Peixe("Nemo");
peixe.apresentar();
peixe.nadar();
// peixe.voar(); // Erro! Peixe não tem mixin Voador
}