690 likes | 798 Views
Programação Orientada a Objetos. Projeto de Classes. Agenda. Projeto baseado na responsabilidade Acoplamento Explícito Implícito Coesão Classes Métodos Refatoração. Projeto. O que torna um projeto bom ou ruim ? Bons projetos Exigem mais esforços à curto prazo .
E N D
ProgramaçãoOrientada a Objetos Projeto de Classes
Agenda • Projetobaseadonaresponsabilidade • Acoplamento • Explícito • Implícito • Coesão • Classes • Métodos • Refatoração
Projeto • O quetorna um projetobomouruim? • Bonsprojetos • Exigemmaisesforços à curtoprazo. • A longoprazo, osesforçossãojustificados. • Implementaçãopoderealizarsuastarefas com classes mal projetadas. • O fato de executarumaaplicaçãonãoindica se elaestabemestruturadaounão.
Princípios • Princípiosquedevem ser seguidos: • Projetobaseadonaresponsabilidade. • Encapsulamento. • Fraco acoplamento. • Alta coesão.
Problemas • Surgememgeralquando: • Programador de manutençãotentafazeralgumasalterações • Corrigirumafalha. • Adicionar nova funcionalidade. • Classes bemprojetadas: • Tarefafácil e óbvia. • Classes mal projetadas: • Tarefamuitodifícil e envolvemuitotrabalho.
Problemas • Grandesaplicações • Taisproblemasocorremdurante a implementação original. • Se o projetocomeça com umaestruturaçãoruim, terminá-lo pode ser muitocomplexo • Programanãopode ser terminado. • Podeconterfalhas. • Demorarmuitomais do quenecessáriopara ser construído.
Adaptar e estenderumaaplicação • Muitos dos efeitos de um projetoruim se tornamevidentesquando se tenta: • Adaptar. • Estender.
World-of-Zuul • Classes bemdocumentadas • Ilustraqueprojetoruimenvolvealgomaisprofundoquesimplesmente a aparênciadaclasseouquanto é boa suadocumentação.
Introdução a Acoplamento • Qualidade de um projeto de classe: • Acoplamento (coupling) • Refere-se a interconectabilidadedaclasse. • Objetoscooperam via interfaces bemdefinidas. • O grau de acoplamentoindica a firmezaqueessas classes estãoconectadas. • Um bomprojeto de classe visa: • Baixograu de acoplamento • Acoplamentofraco • O grau de acoplamentoindicacomo é difícilfazeralterações
Classes fortementeacopladas • Umaalteraçãoemumaclassepodetornarnecessárioalterarváriasoutras classes • Deve-se evitarisso, pois o efeito de fazerumaalteraçãopequenapodefacilmente se propagarportoda a aplicação • Além disso, localizartodososlugaresonde as alteraçõesdevem ser feitas e realmentefazer as alteraçõespode ser difícil e demorados
Classes fracamenteacopladas • Pode-se alterarumaclassesemfazernenhumaalteraçãoemoutras classes.
Introdução a Coesão (cohesion) • Número e diversidade de tarefaspelasquaisumaunidade de umaaplicação é responsável • Classes. • Métodos. • Ideal • Umaunidade de códigodeve ser responsávelporumaunidadecoesa (umatarefaquepode ser vista com umaentidadelógica) • Um métododeveimplementarumaoperaçãológica • Umaclassedeverepresentar um tipo de entidade
Reutilização • Coesão visa reutilização • Se um métodoouumaclasse é responsávelporapenasumacoisabemdefinida • Bemmaisprovávelqueelepossa ser utilizadonovamenteem um contextodiferente.
Vantagemcomplementar de Coesão • Quandoalgumaalteração é necessária, é provávelqueencontre-se todas as partesrelevanteslocalizadasnamesmaunidade
Duplicação de Código • Forte indicador de projetoruim • Problemas: • Qualqueralteraçãoemuma parte deve ser feitanaoutra, casocontrário, a aplicaçãoficainconsistente. • Aumenta o trabalhoque um programador de manutenção tem de fazer e introduzperigo de bugs. • O programadorpodenãoacharcópia do código, nãoalterá-la e assumirque o trabalhoestaconcluído. • Nãohá nada queindiquequeumasegundacópia do códigoexiste • Sintoma de mácoesão
Exemplo de duplicação de código • MétodosprintWelcome() e goRoom()daclasseGame System.out.println("You are " + currentRoom.getDescription()); System.out.print("Exits: "); if(currentRoom.northExit != null) System.out.print("north "); if(currentRoom.eastExit != null) System.out.print("east "); if(currentRoom.southExit != null) System.out.print("south "); if(currentRoom.westExit != null) System.out.print("west "); System.out.println();
Raízes do Erro • Os doismétodosemquestãofazemduascoisas: • printWelcome() imprime a mensagem de boas vindas e imprime as informaçõessobre a localizaçãoatual • goRoom() altera a localizaçãoatual , e imprime as informaçõessobre a localizaçãoatual • Os doismétodosimprimem as informaçõesatuais de localização, masnenhum deles podechamar o outro, porqueelestambémfazemoutrascoisas. Isso é um projetoruim.
Solução do Erro • Um projetomaisaprimoradoutilizaria um métodomaiscoesoseparandoem um únicatarefa a impressão das informaçõesatuais de localização. • Os doismétodospodemfazerchamadas a esse novo métodoquandoprecisaremimprimiressasinformações. • Dessamaneira, não e necessárioescrever o códigoduasvezes, e quandoumaalteração for necessária , seráprecisoumaúnicamodificação.
FazendoExtensões • Tarefa • Adicionaruma nova direção de movimento. • Atualmente: norte, leste, sul e oeste. • Deve-se permitir: paracima e parabaixo.
Localizandocódigorelevante • Duas classes: Room e Game • Room é a classequearmazena a saída de cadasala. • Gameutiliza as informações de saídadasalaatualparaimprimir as informaçõessobresaídas e para se mover de umasalaparaoutra.
ClasseRoom • Adicionardoisnovoscampos • AlterarmetodossetExits(…)
ClasseGame • Maistrabalhosolocalizar as modificações • Localizartodososlugaresexigepaciência e cuidado • Métodosquedevem ser alterados: • createRoom() • printWelcome() • goRoom() • Umapossivelsoluçãoseriaadicionar as novas direçõesemtodosessesmétodos • É a melhorsolução???????????
Acoplamento • O fato de havermuitoslugaresondetodas as saídassãoenumeradas e sintomático de projetoruim. • Aodeclararvariáveis de saídanaclasseRoom • setExits()há um if porsaída • goRoom()há um if porsaída • printLocationInfo()há um if porsaída • Essadecisão de projetocriatrabalho: localizartodosesseslugares e adicionardoisnovoscasos • E se um novo requisito fosse adicionar as direçõescomonoroeste, sudeste????
Soluçãomaisadequada • UsarHashMap<String, Room> paraarmazenar as saídas • Obriga-se a escrevercódigoquepodeoperar com qualquernúmero de saídas • Nãoobriga a tantaalterações no futuro • Essa e umaalteraçãonamaneiracomo a salaarmazenasuasinformações. Teoricamenteessaalteraçaodeveafetarsomente a classeRoom (como as informações de saídasãoarmazenadas), não a interface (o que a salaarmazena)
Soluçãomaisadequada • De maneira ideal , quandoapenas a implementaçãomuda , outras classes nãodeviam ser afetadas. Issoseria um caso de acoplamentofraco. • Emnossoexemplo, issonãofunciona. Se as saídas de Roomforemsubstituídaspor um HashMap, a classeGamenãocompilarámais. • Sintoma de acoplamento forte.
Encapsulamentoparareduziracoplamento • Problema principal: • Uso de campospúblicos • Aotornarpúblicas as saídas, a classeRoomexpôsemsua interface nãoapenas o fato de que tem saídas, masexatamentecomotaisinformaçõessãoarmazenadas. Issoquebra um dos princípiosfundamentais do bomprojeto, o encapsulamento.
Encapsulamento • Diretriz • Ocultarinformações de implementaçãodavisualização • O queumaclassepodefazerdeve ser visível • Como a classe é, não. • Vantagem • Se nenhumaoutraclassesabecomo as informaçõessãoarmazenadas, pode-se facilmentealterarcomoelassãoarmazenadasemquebraroutras classes
ClasseRoomModificada • Impôrseparação entre o que e como • Tornandooscamposprivados • Método de acessoparaobtê-los • A classeGamedeverá ser alteradatambém. Reduzindodrasticamente o código.
ClasseRoomModificada • Até agora nãoalteramos a representação de saída. Somente a interface foilimpa. • A alteraçãoemGame e mínima. Aoinvés de acesso a campospúblicos, o uso de métodos , mas o ganho é significativo. • Agora pode ser alterar, como as saídassãoarmazenadasnaclasseRoomsem se preocupar com a quebra de qualqueroutraclasse. • A representaçãointernaemRoomfoicompletamenteseparadada interface.
ClasseRoomAlterada • Agora que o projetoestácomodeviaestar, a troca dos camposseparadospor um HashMap é fácil. • Vale enfatizarquepode-se fazer a alteraçãosemmesmoverificar se qualquercoisaquebraráemoutra parte. PoisforamalteradosapenasaspectosprivadosdaclasseRoom. A interface permaneceinalterada. • Vantagensdaalteração: • ClasseRoommaiscurta. • MétodogetExit()foireduzidoaoextremo.
ClasseRoomAlterada • Objetivo: inserirduas novas saídas. • MetodosetExitsaindaprecisa de aperfeiçoamento • Interface daClasseRoom • Alteraçõesafetamoutras classes • Não é possívelsepararcompletamente as classes, casocontrárioobjetos de classediferentesnãoseriamcapazes de interagir entre si. • Aoinvés disso, manter o grau de acoplamento o maisbaixopossivel.
MétodosetExit() • public void setExit(String direction, Room neighbor) • Agora, as saídasdasalapodem ser configuradasumasaídaporvez e qualquerdireçãopode ser utilizadaparaumasaída. • Remove-se assimcompletamente a restrição de Room. A classeRoompodearmazenar as direçõesparacima e parabaixo, bemcomoqualqueroutradireçãoquepossaimaginar.
Projetobaseadonaresponsabilidade • Uso de encapsulamentoadequadoreduz o acoplamento e podereduzirsignificativamente a quantidade de trabalhonecessárioparafazeralteraçõesemaplicações. • Poremessenão é o únicofatorqueinfluencia o grau de acoplamento. Outroaspecto é conhecidopelotermoprojetobaseadonaresponsabilidade.
Projetobaseadonaresponsabilidade • Idéia • Cadaclassedeve ser responsávelportratarseuspróprios dados • Adição de novas funcionalidades • Qualclassedevemosadicionar um métodoparaimplementaressa nova função? • Qualclassedeve ser responsávelpelatarefa? • A resposta é: a classeque é responsávelporalguns dados tambémdeve ser responsávelpormanipulá-los.
Responsabilidade e Acoplamento • Versão original do printLocation() com o métodogetExitString() • As informaçõessobresaédaestãoarmazenadassomentenaprópriasala, e a salaque é responsávelporforneceressasinformações. • A salapodefazerissomuitomelhor do quequalqueroutroobjeto, desdequetenhatodo o conhecimentosobre a estrutura de armazenamentointerno dos dados.
Responsabilidade e Acoplamento • Objetivo • Reduziracoplamento • System.out.println(“You are ” + currentRoom.getDescription()); • System.out.println(currentRoom.getExitString()); • Implementaçãoaindapode ser melhorada • Se adicionarmositens as salas? • Oumonstros? • Ououtrosjogadores? • Tal descriçãodeveestarcontidanasala. • Porém se taisalteracoesfossemnecessárias, a classeGamedeve ser alterada (acoplamento)
Responsabilidade e Acoplamento • Nova brechapara o projetobaseadoemresponsabilidade • Roommanteminformaçõessobre a sala • Elatambemdeveproduzirumadescriçãopara a sala public String getLongDescription() { return "You are " + description + ".\n" + getExitString(); } • Na classeGame System.out.println(currentRoom.getLongDescription());
Minimizando as alterações • Outroaspectodaseparação e de princípios de responsabilidade • Procura-se criar um projetoquefacilitealteraçõesposteriores • Idealmenteapenasumaúnicaclasseprecisa ser alteradaparafazerumamodificação • Ocasionalmente, várias classes precisam de alteração, masobjetivamente com o mínimopossível de classes. • Além do mais, as alteraçõesnecessáriasemoutras classes devem ser óbvias, fáceis de detectar e fáceis de executar
Minimizando as alterações • Alcança-se regras de bonsprojetosutilizando: • Projetobaseadonaresponsabilidade • Fracoacoplamento • Alta coesão • Teremmente: • Modificação e extensão • Importanteanteciparque um aspecto do programapodesofreralteração, a fim de facilitaressaalteração.
AcoplamentoImplícito • Campos públicos • Praticaquetalvezcrie forte acoplamento • Necessárioalteraçãoemmais de umaclassepara o quedevia ser uma simples modificação • Campos públicosdevem ser evitados • Porém, háformaspiores de acoplamento • Acoplamentoimplícito • Umaclassedepende de informaçõesinternasdaoutra • Dependêncianãoóbvia • AcoplamentoExplícito • Não é bom • Porém é óbvio (aplicaçãonãocompila)
AcoplamentoImplícito • Novo requisito • Adicionar nova palavra de comandoaojogo • look (imprimir a descriçãodasala e sairnovamente) • Solução • Introduziruma nova palavra de comando, no array validCommandsnaclasseCommandWords • Boa coesão • Aoinvés de definirmos o comando no Parser • Facilitaencontrarondeoscomandosestãodefinidos e acrescentaroutros • O autorestapensandonafrente, assumindoqueoutroscomandospodem ser definidos, e criouumaestruturaquetornaissofácil
AcoplamentoImplícito • Apósfazer a alteração, issonãofunciona. • Aodigitar look nada acontece. • Palavra é reconhecida • Porémnãoháaçãovinculada a ela • Issopode ser corrigidoadicionando o método look naclasseGame. E adicionadomais um if no métodoprocessCommand. • O acoplamento entre as classes Game, Parser, e CommandWordparaser boa • Fácilfazer a extensão
AcoplamentoImplícito • Emitircomando help • Nota-se um pequenoproblema • O novo comandonãoe listado • Fácilde corrigir • Editarstring do métodoprintHelp de Game • Feitorapidamente e nãoparece um grandeproblema • E se talerronãotivessesidonotado? • Vocêpensounesseerro antes de leraqui? • Problema fundamental • Novo comando • Ajudaprecisa ser atualiza • Fácilde esquecertalalteração • O programacompila e executa • O programador de manutençãopodemuitobemacreditarque o trabalhoestaterminado e liberar um programaque agora contemumafalha
AcoplamentoImplícito • Comandosalterados • Texto de ajudadeve ser modificado (acoplamento) • Mas nada no fonte do programaindicaclaramenteessadependência(implícito) • Classebemprojetada • Evitaacoplamentoimplícito • Seguindo a regra do projetobaseadonaresponsabilidade
AcoplamentoImplícito • ClasseCommandWord • Responsávelpelaspalavras de comando • Deve ser responsávelpelasimpressãodas palavras de comando • AdicionarmetodoshowAll() • ClasseGame • printHelp() • Aoinvésde imprimirtextofixo • Invoca um método de um objetoCommandWordparaimprimirtodas as palavras de comando
AcoplamentoImplícito • Gamenãotem referênciaa um objetoCommandWords • Podeser adicionado • Diagrama de classerefletiriaisso (Gameteriarelaçãocom CommandWords) • Setas no diagrama de classesãoumaprimeira boa indicaçãodo quanto um programaé fortementeacoplado. • Maissetas, maisacoplamento • Bonsprojetos • Diagramas com poucassetas
AcoplamentoImplícito • Gamenãoterreferênciaa CommandWordsé uma boa coisa • Issonãodeve ser alterado • Ponto de vista de Game • CommandWordsé detalhe de implementaçãodo Parser • Parser • Retornacomandos • Decisãode usar um CommandWordsparaissoououtracoisaé detalhe de implementação
AcoplamentoImplícito • ProjetoAprimorado • AdicionaremGame • parser.showCommands() • showCommands()emParse • DelegaresponsabilidadeaoobjetoCommandWords
Pensando a frente • Projetoatualé bemmelhorque o original • Contudoé possívelaperfeiçoa-lo aindamais • Característicade um bomprojetista • Capacidade de pensar a frente • O quepode ser mudado? • O quepermanecerainalteradodurantetoda a vida do programa?