Baixe o app para aproveitar ainda mais
Prévia do material em texto
© ELFS 45 • Como já sabemos, a primeira preocupação na POO deve ser identificar as classes que o programa precisa. • Em seguida, devemos pensar quais devem ser os campos e os métodos dessas classes (e, consequentemente, de seus objetos). • Vamos imaginar que um programa precisa tratar com datas (dia/mes/ano) e que para esse programa foi construída a seguinte classe: Data − int dia − int mes − int ano + Data() + Data(int, int, int) + void paraFrente(int) + void paraTras(int) + String toString() − boolean anoBissexto() − int diasDoMes() − void avancar() − void voltar() Algumas questões importantes são: • Por que os campos da classe são privados? • Uma classe pode ter campos públicos? • Por que alguns métodos são privados e outros são públicos? • Por que o método Data() não tem um tipo, como os demais métodos? • Por que existem dois métodos Data()? © ELFS 46 • Por que os campos são privados? Uma classe pode ter campos públicos? • Os campos devem ser privados para garantir que o estado de um objeto seja sempre consistente. Uma classe pode ter campos públicos, desde que não seja possível atribuir novos valores a esses campos (caso das constantes). d.dia = 32; // impossível Data + int dia + int mes + int ano d.dia = 32; // problema Data − int dia − int mes − int ano Com os campos privados o usuário não pode atribuir um valor (válido ou inválido) a um campo. Se for necessário atribuir um valor a um campo, esta atribuição deve ser feita por um método público da classe. Isso garante que a atribuição será sempre válida. public void setDia(int d) { if (d >= 1 && d <= diasDoMes()) dia = d; else System.out.println("Dia incorreto"); } © ELFS 47 • Os métodos públicos que atribuem valores aos campos privados da classe são conhecidos como setters. Esses métodos costumam ser declarados sempre como: setNomeDoCampo(tipo parâmetro) • Classe Data: Data − int dia − int mes − int ano public void setDia(int d) { if (d >= 1 && d <= diasDoMes()) dia = d; else System.out.println("Dia incorreto"); } public void setMes(int m) { if (m >= 1 && m <= 12) mes = m; else System.out.println("Mes incorreto"); } public void setAno(int a) { if (a >= 1) ano = a; else System.out.println("Ano incorreto"); } + void setDia() + void setMes() + void setAno() © ELFS 48 • Uma classe deve também incluir métodos públicos que retornam os valores atuais dos campos privados da classe. Esses métodos são conhecidos como getters e costumam ser declarados como: tipo getNomeDoCampo() • Classe Data: Data − int dia − int mes − int ano public int getDia() { return dia; } public int getMes() { return mes; } public int getAno() { return ano; } + void setDia() + void setMes() + void setAno() + int getDia() + int getMes() + int getAno() Observar que os getters garantem o acesso aos valores dos campos, uma vez que o acesso diretamente a um campo privado não é possível. d = dia; ERRADO! d = getDia(); CERTO! © ELFS 49 • Por que alguns métodos são privados e outros são públicos? • Uma classe pode ter campos e métodos privados ou públicos. • Campos: devem ser privados (para garantir a consistência dos objetos). • Campos públicos: no caso de constantes (valor não pode ser alterado). • Métodos: em geral, devem ser públicos (API da classe) • Métodos privados: quando são internos à classe (não estão na API) • Em geral, os campos e métodos de uma classe podem ser: onde (package) indica que nenhum modificador foi usado. Nível de acesso Modificador Classe Pacote Subclasse Todas public S S S S protected S S S N (package) S S N N private S N N N © ELFS 50 • Por que o método Data() não tem um tipo, como os demais métodos? E por que existem dois métodos Data()? • Porque, para a classe Data, o método Data() é um construtor. O objetivo de um método construtor é construir objetos da classe. • Os construtores são métodos especiais que têm o mesmo nome da classe e garantem que cada objeto da classe inicia sua existência em um estado consistente. • Construtores, como qualquer outro método, podem receber parâmetros. • Um construtor não retorna valor algum, nem mesmo do tipo void. • Toda classe deve ter um construtor. Se nenhum construtor for declarado no corpo da classe, um construtor padrão será incluído na compilação. Este construtor padrão não tem parâmetros e permite que se criem objetos de uma classe utilizando a instrução new Classe(). • Se em uma classe que não tinha um construtor explícito, for declarado um construtor, essa classe irá perder o construtor padrão. Se o construtor incluído tiver parâmetros, todas as chamadas posteriores a new Classe() causarão erros de compilação. Portanto, ao definir construtores em uma classe, deve-se sempre definir também um construtor sem parâmetros. • Exemplo. Vamos considerar a representação de um horário utiliza 3 campos inteiros: hor, min e seg. public class Horario { private int hor; private int min; private int seg; public Horario() { setHora(0); setMinuto(0); setSegundo(0); } public Horario(int h, int m, int s) { setHora(h); setMinuto(m); setSegundo(s); } © ELFS 51 Horario.java Uma classe pode ter mais de um construtor. Os construtores devem chamar os setters para atribuir valores aos campos da classe. public int getHora() { return hor; } public int getMinuto() { return min; } public int getSegundo() { return seg; } public final void setHora(int h) { hor = (( h >= 0 && h < 24 )? h : 0); } public final void setMinuto(int m) { min = (( m >= 0 && m < 60 )? m : 0); } public final void setSegundo(int s) { seg = (( s >= 0 && s < 60 )? s : 0); } © ELFS 52 Esses são os setters da classe. Observar que os setters devem ser sempre final void. Esses são os getters da classe. Observar que os getters são métodos que têm o mesmo tipo que o campo da classe a que se referem. © ELFS 53 @Override public String toString() { DecimalFormat df = new DecimalFormat("00"); return (df.format(getHora()) + ":" + df.format(getMinuto()) + ":" + df.format(getSegundo())); } } © ELFS 53 public class UsaHorario { public static void main(String[] args) { Horario h = new Horario(); System.out.println(h.toString()); h.setHora(15); h.setMinuto(30); System.out.println(h); h = new Horario(20,60,99); System.out.println(h); } } UsaHorario.java Note que o método toString() pode ficar implícito. © ELFS 54 • A classe UsaHorario utiliza a classe Horario. Ou seja, a classe UsaHorario é um usuário da classe Horario. • Os usuários de uma classe utilizam a parte pública da classe (a API da classe) e desconhecem como os campos e os métodos da classe foram implementados. • Exemplo: se, em vez de representar um horário por três valores inteiros (hor, min, seg), um horário for representado como o número de segundos desde a zero-hora, os usuários poderiam utilizar os mesmos métodos públicos e obter os mesmos resultados sem se dar conta disso. É claro que os métodos teriam que ser reimplementados, considerando essa nova representação do horário. ! • Se a implementação de uma classe é alterada, desde que a API da classe permaneça a mesma, o código- fonte dos usuários da classe não precisa ser alterado. Isso torna muito mais fácilmodificar e distribuir sistemas. Horario − int hor − int min − int seg + Horario() + Horario(int h, int m, int s) + int getHora() + int getMinuto() + int getSegundo() + final void setHora() + final void setMinuto() + final void setSegundo() + String toString() © ELFS 55 Exemplo: public class Horario { private int tempo; public Horario() { setHora(0); setMinuto(0); setSegundo(0); } public Horario(int h, int m, int s) { setHora(h); setMinuto(m); setSegundo(s); } Horario.java Até aqui nada mudou, pois os construtores chamam os setters para atribuir o valor correto ao campo da classe. © ELFS 56 public int getHora() { return (tempo/3600); } public int getMinuto() { return ((tempo - 3600*getHora())/60); } public int getSegundo() { return (tempo - 3600*getHora() - 60*getMinuto()); } public final void setHora(int h) { int hh = ((h >= 0 && h < 24)? h : 0); tempo = hh*3600 + getMinuto()*60 + getSegundo(); } public final void setMinuto(int m) { int mm = ((m >= 0 && m < 60)? m : 0); tempo = getHora()*3600 + mm*60 + getSegundo(); } public final void setSegundo(int s) { int ss = ((s >= 0 && s < 60)? s : 0); tempo = getHora()*3600 + getMinuto()*60 + ss; } A implementação dos getters e setters muda, pois estes métodos dependem de como são representados os campos da classe. public class UsaHorario { public static void main(String args[]) { Horario h = new Horario(); System.out.println(h.toString()); h.setHora(15); h.setMinuto(30); System.out.println(h); h = new Horario(20,60,99); System.out.println(h); } } © ELFS 57 @Override public String toString() { DecimalFormat df = new DecimalFormat("00"); return (df.format(getHora()) + ":" + df.format(getMinuto()) + ":" + df.format(getSegundo())); } UsaHorario.java Como a API da classe não mudou, a mesma classe usuária anterior pode ser usada agora. O método toString() também continua inalterado, pois utiliza os getters. © ELFS 58 • Uma classe pode conter vários métodos com o mesmo nome, desde que as assinaturas dos métodos sejam diferentes. Isto é chamado de sobrecarga de método. • Assinatura: combinação do nome do método com sua lista de parâmetros. • Quando um método sobrecarregado é chamado, o compilador seleciona o método adequado examinando sua assinatura. • Em geral, os construtores de uma classe são métodos sobrecarregados. public int quadrado(int x) { return x * x; } public double quadrado(double x) { return x * x; } Assinatura: quadrado.int Assinatura: quadrado.double Se houvesse um outro método: public double quadrado(int z) o que ocorreria?
Compartilhar