Olá! Bem vindo a mais uma aula do laboratório de programação orientada a objetos. Hoje nós vamos falar sobre classes abstratas e interfaces. São conceitos bem importantes de orientação a objetos. Primeiro, vamos começar pelas classes abstratas. O que é uma classe abstrata? É uma classe como outra qualquer, mas ela indica que há tipo de objeto que vai possuir determinado método, mas ela não define a implementação desse método, ela define só a assinatura do método, sem especificar o código que implementa aquele método. Por exemplo, a gente poderia ter uma classe filme, que eu poderia deixar aberto alguns métodos dessa classe filme, sem implementação, porque não sei implementar. Por exemplo, para tocar filme do tipo mp4 é jeito completamente diferente de tocar do tipo AVI. Precisaria de algoritmo diferente, de código diferente. Então, nessa classe filme, a gente pode deixar indicado que vai ter método chamado play, por exemplo, para tocar o filme. É fundamental que tenha método play mas a gente não sabe implementar, então a gente define método abstrato. Definir método abstrato é colocar uma assinatura do método dizendo qual o nome do método, quais são os parâmetros, que tipo de valor ele devolve, mas sem ter essa implementação. Se uma classe tem pelo menos método abstrato, então, essa classe se torna uma classe abstrata, e uma classe abstrata eu não posso ter uma instância dela porque falta pedaço da implementação. Como que eu crio uma instância então? Eu preciso criar uma subclasse, dessa classe abstrata, que vai implementar este método que está faltando, seguindo exatamente a mesma assinatura do método, do mesmo nome, dos mesmos parâmetros, mas com o código fonte. E nesse nosso exemplo, o filme mp4 implementaria o código do play, completamente diferente do código FilmeAVI e do FilmeOgg. Como que a gente faria isso aqui no eclipse? Deixa eu criar novo projeto. Vamos chamar este projeto de teste abstrato. E a gente cria este projeto. Eu não vou criar módulo no momento e aqui no teste abstrato eu vou criar uma nova classe. Eu vou dar o nome da classe, por exemplo, movie, filme inglês. E eu poderia definir já aqui que essa é uma classe abstrata, ela automaticamente já preencheria para a gente. Vamos fazer desta forma, você vai ver, ele simplesmente vai preencher. Ele escreveu, essa classe movie, que eu criei é abstract, é uma classe abstrata. Aqui dentro da classe abstrata eu posso ter alguns dos métodos, sendo métodos normais, que eu implemento, por exemplo, o método int que devolve a duração minutos do filme. E eu poderia ter devolvendo determinado valor. Como se fosse fazer uma implementação meio boba constante, que sempre tem que o filme dura 120 minutos, só para título de ilustração. Então, esse não é método abstrato, esse é o método normal. Mas eu poderia agora ter método abstrato, por exemplo, para isso eu digo que o método é abstract Vamos lá, abstract e o nome, a assinatura do método, por exemplo, void play, que supostamente quando eu chamar esse método play, ele vai executar o filme. Só que, vez de ter a implementação, eu simplesmente coloco ponto e vírgula e termina nosso método. Salvei, está tudo bem. Essa é uma classe que é abstrata porque dos métodos é abstrato, pode ser 2, 3, 4 métodos abstratos, mas pelo menos ela está indicando que coisas do tipo movie tem que ter play, mas ainda não sei implementar o play, quem vai implementar são as minhas subclasses. Particular, se eu se eu quiser instanciar esse movie, fizer new no movie, ele vai dar erro de compilação falando que é uma classe abstrata, você não pode criar. Então, se eu quiser, o que eu vou ter que fazer? Eu vou ter que criar aqui uma subclasse, por exemplo, mp4 movie e eu defino que a super classe vai ser a minha classe movie e só isso. Então aqui estou na minha classe MP4 movie que extend movie. E essa aqui não é uma classe abstrata, é uma classe concreta. O eclipse já preencheu isso para mim, porque ele já viu, se você está estendendo uma classe abstrata, então você precisa sobrescrever pelo menos dos métodos da classe abstrata. Se eu não sobrescrever, ficou faltando implementar algum dos métodos da classe abstrata que é minha classe mãe, eu também vou ser uma classe abstrata. porque eu só vou conseguir ser uma classe não abstrata quando eu tenho a implementação de todos os métodos. Então poderia ter o código do como se toca o filme. Como aqui a gente não vai fazer código de tocar filme, a gente pode sempre imprimir 'que filme legal'. Println. Agora salvou, agora note que apareceu.. salvou, está funcionando. Já posso agora instanciar objeto dessa classe MP4 movie. Agora note que apareceu essa palavra reservada aqui, override. Palavra reservado não, essa aqui é uma anotação, tem arroba, é uma anotação Java. Na verdade, se eu remover isso, não tem problema nenhum, vai funcionar do mesmo jeito. O eclipse coloca esse override, porque, se tem aquele override ele está querrendo dizer para o compilador que este método está sobrescrevendo método de uma classe abstrata, que está cima. Particular, se eu me engano e vez de colocar o nome play e coloco play movie, faço algo assim diferente, por exemplo e mando salvar, ele vai dar uma mensagem de erro. Neste caso está dando duas mensagens de erro. Primeiro, ele está avisando que o método play movie, dessa classe, deveria ter sobrescrito ou implementado método da super classe. Porquê? Porque tem esse override e, na verdade, na superclasse não tem nenhum método da classe movie. Fora isso ele deu outro erro aqui. Está falando que essa classe MP4 movie, deveria implementar o método abstrato da classe mãe, que é a classe movie.play e ele não está implementando-. Então, deu dois erros de compilação, particular, vamos supor que eu colocasse aqui o play, método play. Se eu colocar o método play sumiu esse erro de compilação que tinha cima. Porque agora sim, essa classe MP4 movie já implementa o play, então, está correto. Continua dando este erro aqui, como a gente colocou o override, o override é lembrete compilador de que este método está sobrescrevendo método da classe mãe, na verdade agora não está. Então, o que a gente faria neste caso seria simplesmente colocar o nome certo e deixaria o override. Assim, funciona. Este é exemplo de classes abstratas JAVA, são usadas de vez quando mas não é muito comum. Tem uma coisa que a gente vai ver agora que é muito mais comum do que as classes abstratas. O que será? É isso aqui! Interface. Interface é uma coisa fundamental orientação a objetos e também muito usada JAVA. O que é uma interface? Na verdade, é uma classe abstrata radical, é uma classe puramente abstrata, o que significa isso? Que todos os seus métodos são abstratos, uma interface não implementa códigos de nenhum método, ele só lista as assinaturas dos métodos. Uma interface é, na verdade, conjunto de operações que outras classes vão implementar. Não tem nenhuma implementação de código numa interface. Esses códigos, esses métodos, tem que ser implementados posteriormente por classes, que a gente usa a palavra reservada implements para explicar isso. Então JAVA eu vou poder escrever coisa desse tipo. Uma classe Cx, por exemplo, Cx é o nome da classe, implementa a interface Y. Então, o nome da interface é interfaceY e o nome da classe é Cx. Com essa linha estou dizendo que a classe Cx implementa a interface y e eu abro chaves, evem o código da classe. Normalmente, para uma interface, você pode ter várias classes diferentes implementando aquela mesma interface. Uma interface representa comportamento comum, mas você pode ter várias classes diferentes implementando aquele comportamento de diferentes formas. E note que a relação entre interface e classe, não tem a ver com herança, inclusive o implements, para definir herança, a gente usava o extends. uma classe Cx ela não estende a interfaceY, ela implementa a interfaceY. Na verdade você pode ter toda uma hierarquia de classes de lado e algumas dessas classes implementam interfaces diferentes, são coisas independentes, a hierarquia de classes e a implementação de interfaces. Tem pequeno detalhe da linguagem Java que você pode também ter atributos nessa interface, mas os atributos, obrigatoriamente, são constantes. Então, mesmo que você não diga, implicitamente eles vão ser do tipo public static final. Se naquela sua interface faz sentido definir alguma constante, você pode colocá-la como atributo da interface, mas não é muito comum, não é obrigatório. Depende de caso a caso. Vamos ver exemplo agora. Vamos supor que você vai fazer videogame. Eu gosto sempre de dar de exercício videogame 2D de batalha espacial ou que, por exemplo, tenha o planeta Terra e tem asteroides que estão caindo na Terra e, para proteger o planeta Terra, você tem que ir com a sua nave, atirando nos asteroides, para os destruir. Esse é videogame bem interessante de se fazer e, jeito normal de implementar é você ter objetos, uma interface que representa objeto que aparece na tela. E qualquer objeto, pode ser asteroide, uma nave, tiro, planeta. A nave pode ser nave amiga, nave inimiga. Cada tem o seu comportamento diferente, mas todos eles têm que seguir determinado protocolo, grupo de mensagens padrão. Por exemplo, uma mensagem para plotar ele na tela, para saber que posição XY da tela ele está, para fazer ele mover para uma outra posição XY. Todos são comandos comuns que todos esses objetos espaciais devem obedecer. Para fazer isso a gente poderia implementar uma interface ObjetoEspacial. Como a gente faria isso no Eclipse? A gente pode vir aqui e fazer New, Interface. Está vendo aqui? New, Interface? Ao fazer o New, Interface ele pergunta 'qual é o nome da interface?'. Nesse nosso caso vai ser ObjetoEspacial e a gente implementa essa nova interface. Java é assim. Public interface ObjetoEspacial. Esse public aqui é opcional. E a gente agora define o que essa interface vai ter. Se a gente quiser pode definir uma constante, não é muito comum, mas se quiser definir uma constante, uma constante geral no universo, no nosso universo espacial, fica ali definido que k vale 42, por exemplo. Mas que tipo de métodos a gente poderia querer ter? A gente poderia querer ter algo do tipo saber a posição X e Y daquele objeto. Por exemplo, poderia ter método getPosiçãoX que vai devolver a posição daquele objeto no eixo X e getPosiçaoY para pegar o eixo Y. Mas vamos parar aqui. Eu quero mostrar agora então. Isso aqui é só uma interface, por enquanto, com único método. Vamos criar uma classe que vai implementar essa interface. Como que eu faria isso? Depois a gente continua estendendo a interface. De novo eu venho aqui e dou New, Classe, e na hora de definir a classe eu tenho que dar nome. Então, eu vou chamar de naves, NaveEspacial e eu posso adicionar uma interface que ele implementa. Ele vai implementar esse objeto espacial. Se eu quiser, a minha superclasse pode ser outra. Por exemplo, eu posso ter uma NaveEspacial e depois NaveAmiga e NaveInimiga. Tanto NaveAmiga quanto NaveInimiga podem ter implementações diferentes e tem a superclasse NaveEspacial. Mas ambas podem implementar essa interface ObjetoEspacial e outras interfaces também. Nada impede que uma classe implemente várias interfaces. Mas vamos criar isto e ver como é que fica esse código. Então ele fez, a classe NaveEspacial implementa ObjetoEspacial, é tipo específico de ObjetoEspacial. E o Eclipse já pré preencheu para mim os métodos que precisam ser implementados. No caso ele pré preenche com a lista de métodos do meu ObjetoEspacial. Nesse caso ele pegou esse getPosiçãoX e colocou uma implementação qualquer, por enquanto, simplesmente devolve zero para a gente complementar. Então a ideia é que você viria aqui por exemplo, eu poderia ter atributo X e Y que teria a posição e a gente devolver aqui o valor com x. Tipicamente, você vai ter mais coisas numa interface. Particular poderia ter o getPosiçãoX, getPosiçãoY. Depois se eu quero mudar, a minha nave espacial está numa posição da tela e eu quero mudar para outra posição da tela, eu poderia ter set, setPosiçãoX e setPosiçãoY onde eu dou o novo valor para o X e Y e ele desenha. Assim, se eu quiser fazer objeto se movimentar pela tela, por exemplo, a cada décimo de segundo eu posso mudar pouco, pixel, e ele vai mudando, assim, três pixels por segundo. Então setPosiçãoX, setPosiçãoY. Poderiam ter outras coisas que objetos espaciais fazem. Por exemplo, os objetos espaciais nesses tipos de jogos eles sabem se explodir. Então, por exemplo, pode ter exploda. O exploda aqui pode vir com parâmetro intensidadeDaExplosão. Uma explosãozinha, uma explosão enorme. Que outras coisas objeto espacial poderia fazer? Poderia ter assim estou chutando agora, método boolean vai dizer se esse meu objeto ele está colidindo, colide com outro objeto. [SOM] E ele vai devolver verdadeiro ou falso. Então, se eu tenho dois objetos, por exemplo asteroide e uma nave, eu quero saber se eles estão colidindo. Porque se eles colidirem, o asteroide destrói a nave espacial. Ou se objeto espacial pode ser tiro na minha nave ou se dispara míssil. Eu quero saber se o míssil está colidindo com o asteroide. Se o míssil colidir com o asteroide eu vou chamar o método exploda no míssil e no asteroide para que tudo se exploda. Quero mais é que tudo se exploda mesmo. O que mais que a gente pode fazer? O ObjetoEspacial poderia tocar uma musiquinha dele, poderia ter MP3 e ele falar suaMúsica. Eu pergunto para ele a música e ele devolve o MP3, que é a música dele. O que eu fiz aqui de errado? Ele está dizendo que não conhece a classe MP3. Tudo bem, obviamente a gente precisa criar a classe MP3 depois. E outras coisas. O ObjetoEspacial pode ter nome, ele pode ter uma descrição, por exemplo, botando o mouse cima aparece a descrição. [SOM] Por que ele não botou? [INAUDÍVEL] [INAUDÍVEL]. Vamos para simplificar, por enquanto, eu vou colocar byte array, que é outro jeito de você inventar uma música. Uma sequência de bytes com arquivo MP3 lá dentro. Fiz assim para mudar erro de configuração. Então agora estamos com uma bela interface ObjetoEspacial com monte de coisa que dá para fazer [INAUDÍVEL] e eu poderia implementar uma outra coisa, míssil, asteroide, uma nave inimiga. Vamos implementar planeta. Vamos fazer uma coisa bem animada. Eu crio uma classe, a minha classe vai ser míssil e eu coloco a interface e ele implementa a interface ObjetoEspacial e o Eclipse já coloca todos esses métodos que eu preciso implementar. Provavelmente eu colocaria aqui o int x,y, e eu teria que reimplementar esses métodos aqui, para ser função do x ou do y. Eu teria que fazer a implementação do exploda, o que acontece com o exploda, fazer o código para ver a colisão, a música, o nome e a descrição. Esse é só exemplo de como é importante a gente poder definir tipos comuns, para uma interface definir tipo, nesse caso é tipo Objeto Espacial, sem definir o comportamento. Ou seja, não tem nenhum código, só tem as operações que aquele tipo de objeto entende, simplesmente, quais são as mensagens que aquele objeto entende, sem dizer o que ele faz quando recebe a mensagem. Quem diz o que ele faz é uma classe que implementa aquele objeto espacial. Eu poderia ter míssil e implementar mais do que uma coisa. Míssil poderia implementar objeto espacial e também uma bomba, por exemplo. Eu posso ter uma interface chamada bomba e, o que estou dizendo, que o míssil implementa não só os métodos da interface objeto espacial, como todos os métodos da classe bomba, porque o míssil também se comporta como uma bomba, além de ser objeto espacial. Esse é o nosso exemplo. Daqui a pouco você vão exercitar. Com exercícios, vocês vão implementar interfaces e classes. Definir interfaces e implementar classes. Dois detalhes aqui sobre interfaces. Lembra que eu falei que JAVA não permite herança múltipla de classes. Mas permite herança múltipla de interfaces. Você pode ter uma classe que implementa várias interfaces. Não tem problema nenhum, até é comum. Além disso, é possível também ter herança de interfaces e a herança de interfaces também usa o extends. Então, você pode ter uma interface objeto espacial e depois uma subinterface, que você vai usar o extends para definir, que é tipo específico de objeto espacial, sei lá, objeto espacial luminoso, que emite luz também ou emite radiação. E ele vai ter todos os métodos daquela interface mais da interface mãe, mais os acrescentados nos novos métodos na interface. Não é tão comum assim. É muito comum a gente ver classes implementando uma interface ou classes implementando várias interfaces. Ter hierarquias de classes também é uma coisa muito comum. Hierarquia de interfaces é pouco mais raro, mas pode acontecer JAVA. São dois detalhes interessantes. Resumindo o que a gente viu hoje, classes abstratas e interfaces são formas de se definir o comportamento esperado de tipo ou de grupo de objetos, sem definir completamente a implementação. Nas classes abstratas pelo menos dos métodos é abstrato. Numa interface todos os métodos são abstratos, ou seja, nenhum deles tem código. Ter uma boa prática de orientação a objetos é quando a gente está escrevendo código que usa outras classes, outros objetos, a gente não pensar na implementação desses objetos e sim pensar na interface dos outros objetos. Tem uma coisa que se repete bastante que é o seguinte, programem para as interfaces e não para as implementações. Ou seja, sempre pense qual a interface que aquela classe oferece. Não fica pensando como é que aquela outra classe implementa as coisas. Porquê? Porque essa implementação interna muda com bastante frequência. Se você fizer código que depende da implementação interna de várias outras classes, seu código vai ficar muito amarrado e qualquer mudança que aconteça nessas outras classes, você vai ter de mexer no seu código. Se o seu sistema é muito amarrado no outro, você vai ter que ficar dando manutenção, mexendo num monte de coisas. Vai ser difícil fazer mudanças no código. Por outro lado, se você seguir essa ideia de programar para as interfaces, as interfaces nos protegem sobre o que acontece por trás do pano. Você pode mexer monte na implementação da classe, desde que a interface não mude, o código que está para fora está protegido dessas mudanças que acontecem lá dentro. Então, é isso. Daqui a pouco eu quero ver vocês experimentando, exercitando as interfaces. Obrigado pela presença mais esta videoaula. [SOM]