A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Projeto de Classes.  Projeto baseado na responsabilidade  Acoplamento ◦ Explícito ◦ Implícito  Coesão ◦ Classes ◦ Métodos  Refatoração.

Apresentações semelhantes


Apresentação em tema: "Projeto de Classes.  Projeto baseado na responsabilidade  Acoplamento ◦ Explícito ◦ Implícito  Coesão ◦ Classes ◦ Métodos  Refatoração."— Transcrição da apresentação:

1 Projeto de Classes

2  Projeto baseado na responsabilidade  Acoplamento ◦ Explícito ◦ Implícito  Coesão ◦ Classes ◦ Métodos  Refatoração

3  O que torna um projeto bom ou ruim?  Bons projetos ◦ Exigem mais esforços à curto prazo. ◦ A longo prazo, os esforços são justificados.  Implementação pode realizar suas tarefas com classes mal projetadas. ◦ O fato de executar uma aplicação não indica se ela esta bem estruturada ou não.

4  Princípios que devem ser seguidos: ◦ Projeto baseado na responsabilidade. ◦ Encapsulamento. ◦ Fraco acoplamento. ◦ Alta coesão.

5  Surgem em geral quando: ◦ Programador de manutenção tenta fazer algumas alterações  Corrigir uma falha.  Adicionar nova funcionalidade.  Classes bem projetadas: ◦ Tarefa fácil e óbvia.  Classes mal projetadas: ◦ Tarefa muito difícil e envolve muito trabalho.

6  Grandes aplicações ◦ Tais problemas ocorrem durante a implementação original. ◦ Se o projeto começa com uma estruturação ruim, terminá-lo pode ser muito complexo  Programa não pode ser terminado.  Pode conter falhas.  Demorar muito mais do que necessário para ser construído.

7  Muitos dos efeitos de um projeto ruim se tornam evidentes quando se tenta: ◦ Adaptar. ◦ Estender.

8

9  Classes bem documentadas  Ilustra que projeto ruim envolve algo mais profundo que simplesmente a aparência da classe ou quanto é boa sua documentação.

10  Qualidade de um projeto de classe: ◦ Acoplamento (coupling)  Refere-se a interconectabilidade da classe.  Objetos cooperam via interfaces bem definidas.  O grau de acoplamento indica a firmeza que essas classes estão conectadas.  Um bom projeto de classe visa:  Baixo grau de acoplamento  Acoplamento fraco  O grau de acoplamento indica como é difícil fazer alterações

11  Uma alteração em uma classe pode tornar necessário alterar várias outras classes  Deve-se evitar isso, pois o efeito de fazer uma alteração pequena pode facilmente se propagar por toda a aplicação  Além disso, localizar todos os lugares onde as alterações devem ser feitas e realmente fazer as alterações pode ser difícil e demorados

12  Pode-se alterar uma classe sem fazer nenhuma alteração em outras classes.

13  Número e diversidade de tarefas pelas quais uma unidade de uma aplicação é responsável ◦ Classes. ◦ Métodos.  Ideal ◦ Uma unidade de código deve ser responsável por uma unidade coesa (uma tarefa que pode ser vista com uma entidade lógica)  Um método deve implementar uma operação lógica  Uma classe deve representar um tipo de entidade

14  Coesão visa reutilização ◦ Se um método ou uma classe é responsável por apenas uma coisa bem definida ◦ Bem mais provável que ele possa ser utilizado novamente em um contexto diferente.

15  Quando alguma alteração é necessária, é provável que encontre-se todas as partes relevantes localizadas na mesma unidade

16  Forte indicador de projeto ruim  Problemas: ◦ Qualquer alteração em uma parte deve ser feita na outra, caso contrário, a aplicação fica inconsistente. ◦ Aumenta o trabalho que um programador de manutenção tem de fazer e introduz perigo de bugs.  O programador pode não achar cópia do código, não alterá-la e assumir que o trabalho esta concluído.  Não há nada que indique que uma segunda cópia do código existe  Sintoma de má coesão

17  Métodos printWelcome() e goRoom() da classe Game 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();

18  Os dois métodos em questão fazem duas coisas: ◦ printWelcome() imprime a mensagem de boas vindas e imprime as informações sobre a localização atual ◦ goRoom() altera a localização atual, e imprime as informações sobre a localização atual  Os dois métodos imprimem as informações atuais de localização, mas nenhum deles pode chamar o outro, porque eles também fazem outras coisas. Isso é um projeto ruim.

19  Um projeto mais aprimorado utilizaria um método mais coeso separando em um única tarefa a impressão das informações atuais de localização.  Os dois métodos podem fazer chamadas a esse novo método quando precisarem imprimir essas informações.  Dessa maneira, não e necessário escrever o código duas vezes, e quando uma alteração for necessária, será preciso uma única modificação.

20  Tarefa ◦ Adicionar uma nova direção de movimento. ◦ Atualmente: norte, leste, sul e oeste. ◦ Deve-se permitir: para cima e para baixo.

21  Duas classes: Room e Game  Room é a classe que armazena a saída de cada sala.  Game utiliza as informações de saída da sala atual para imprimir as informações sobre saídas e para se mover de uma sala para outra.

22  Adicionar dois novos campos  Alterar metodos setExits(…)

23  Mais trabalhoso localizar as modificações ◦ Localizar todos os lugares exige paciência e cuidado ◦ Métodos que devem ser alterados:  createRoom()  printWelcome()  goRoom() ◦ Uma possivel solução seria adicionar as novas direções em todos esses métodos  É a melhor solução???????????

24  O fato de haver muitos lugares onde todas as saídas são enumeradas e sintomático de projeto ruim. ◦ Ao declarar variáveis de saída na classe Room  setExits()há um if por saída  goRoom() há um if por saída  printLocationInfo() há um if por saída ◦ Essa decisão de projeto cria trabalho: localizar todos esses lugares e adicionar dois novos casos ◦ E se um novo requisito fosse adicionar as direções como noroeste, sudeste????

25  Usar HashMap para armazenar as saídas ◦ Obriga-se a escrever código que pode operar com qualquer número de saídas ◦ Não obriga a tanta alterações no futuro  Essa e uma alteração na maneira como a sala armazena suas informações. Teoricamente essa alteraçao deve afetar somente a classe Room (como as informações de saída são armazenadas), não a interface (o que a sala armazena)

26  De maneira ideal, quando apenas a implementação muda, outras classes não deviam ser afetadas. Isso seria um caso de acoplamento fraco.  Em nosso exemplo, isso não funciona. Se as saídas de Room forem substituídas por um HashMap, a classe Game não compilará mais.  Sintoma de acoplamento forte.

27  Problema principal: ◦ Uso de campos públicos ◦ Ao tornar públicas as saídas, a classe Room expôs em sua interface não apenas o fato de que tem saídas, mas exatamente como tais informações são armazenadas. Isso quebra um dos princípios fundamentais do bom projeto, o encapsulamento.

28  Diretriz ◦ Ocultar informações de implementação da visualização  O que uma classe pode fazer deve ser visível  Como a classe é, não.  Vantagem ◦ Se nenhuma outra classe sabe como as informações são armazenadas, pode-se facilmente alterar como elas são armazenadas em quebrar outras classes

29  Impôr separação entre o que e como ◦ Tornando os campos privados ◦ Método de acesso para obtê-los  A classe Game deverá ser alterada também. Reduzindo drasticamente o código.

30  Até agora não alteramos a representação de saída. Somente a interface foi limpa.  A alteração em Game e mínima. Ao invés de acesso a campos públicos, o uso de métodos, mas o ganho é significativo.  Agora pode ser alterar, como as saídas são armazenadas na classe Room sem se preocupar com a quebra de qualquer outra classe. ◦ A representação interna em Room foi completamente separada da interface.

31  Agora que o projeto está como devia estar, a troca dos campos separados por um HashMap é fácil.  Vale enfatizar que pode-se fazer a alteração sem mesmo verificar se qualquer coisa quebrará em outra parte. Pois foram alterados apenas aspectos privados da classe Room. A interface permanece inalterada.  Vantagens da alteração: ◦ Classe Room mais curta. ◦ Método getExit() foi reduzido ao extremo.

32  Objetivo: inserir duas novas saídas.  Metodo setExits ainda precisa de aperfeiçoamento  Interface da Classe Room  Alterações afetam outras classes  Não é possível separar completamente as classes, caso contrário objetos de classe diferentes não seriam capazes de interagir entre si.  Ao invés disso, manter o grau de acoplamento o mais baixo possivel.

33  public void setExit(String direction, Room neighbor)  Agora, as saídas da sala podem ser configuradas uma saída por vez e qualquer direção pode ser utilizada para uma saída.  Remove-se assim completamente a restrição de Room. A classe Room pode armazenar as direções para cima e para baixo, bem como qualquer outra direção que possa imaginar.

34  Uso de encapsulamento adequado reduz o acoplamento e pode reduzir significativamente a quantidade de trabalho necessário para fazer alterações em aplicações.  Porem esse não é o único fator que influencia o grau de acoplamento. Outro aspecto é conhecido pelo termo projeto baseado na responsabilidade.

35  Idéia ◦ Cada classe deve ser responsável por tratar seus próprios dados  Adição de novas funcionalidades ◦ Qual classe devemos adicionar um método para implementar essa nova função? ◦ Qual classe deve ser responsável pela tarefa? ◦ A resposta é: a classe que é responsável por alguns dados também deve ser responsável por manipulá- los.

36  Versão original do printLocation() com o método getExitString()  As informações sobre saéda estão armazenadas somente na própria sala, e a sala que é responsável por fornecer essas informações.  A sala pode fazer isso muito melhor do que qualquer outro objeto, desde que tenha todo o conhecimento sobre a estrutura de armazenamento interno dos dados.

37  Objetivo ◦ Reduzir acoplamento  System.out.println(“You are ” + currentRoom.getDescription());  System.out.println(currentRoom.getExitString());  Implementação ainda pode ser melhorada ◦ Se adicionarmos itens as salas? ◦ Ou monstros? ◦ Ou outros jogadores? ◦ Tal descrição deve estar contida na sala. ◦ Porém se tais alteracoes fossem necessárias, a classe Game deve ser alterada (acoplamento)

38  Nova brecha para o projeto baseado em responsabilidade  Room mantem informações sobre a sala  Ela tambem deve produzir uma descrição para a sala public String getLongDescription() { return "You are " + description + ".\n" + getExitString(); }  Na classe Game System.out.println(currentRoom.getLongDescription());

39  Outro aspecto da separação e de princípios de responsabilidade  Procura-se criar um projeto que facilite alterações posteriores  Idealmente apenas uma única classe precisa ser alterada para fazer uma modificação  Ocasionalmente, várias classes precisam de alteração, mas objetivamente com o mínimo possível de classes.  Além do mais, as alterações necessárias em outras classes devem ser óbvias, fáceis de detectar e fáceis de executar

40  Alcança-se regras de bons projetos utilizando: ◦ Projeto baseado na responsabilidade ◦ Fraco acoplamento ◦ Alta coesão ◦ Ter em mente:  Modificação e extensão  Importante antecipar que um aspecto do programa pode sofrer alteração, a fim de facilitar essa alteração.

41  Campos públicos ◦ Pratica que talvez crie forte acoplamento  Necessário alteração em mais de uma classe para o que devia ser uma simples modificação ◦ Campos públicos devem ser evitados  Porém, há formas piores de acoplamento ◦ Acoplamento implícito  Uma classe depende de informações internas da outra  Dependência não óbvia  Acoplamento Explícito ◦ Não é bom ◦ Porém é óbvio (aplicação não compila)

42  Novo requisito ◦ Adicionar nova palavra de comando ao jogo  look (imprimir a descrição da sala e sair novamente)  Solução ◦ Introduzir uma nova palavra de comando, no array validCommands na classe CommandWords ◦ Boa coesão  Ao invés de definirmos o comando no Parser  Facilita encontrar onde os comandos estão definidos e acrescentar outros  O autor esta pensando na frente, assumindo que outros comandos podem ser definidos, e criou uma estrutura que torna isso fácil

43  Após fazer a alteração, isso não funciona.  Ao digitar look nada acontece. ◦ Palavra é reconhecida ◦ Porém não há ação vinculada a ela  Isso pode ser corrigido adicionando o método look na classe Game. E adicionado mais um if no método processCommand.  O acoplamento entre as classes Game, Parser, e CommandWor dpara ser boa ◦ Fácil fazer a extensão

44  Emitir comando help ◦ Nota-se um pequeno problema  O novo comando não e listado ◦ Fácil de corrigir  Editar string do método printHelp de Game  Feito rapidamente e não parece um grande problema ◦ E se tal erro não tivesse sido notado? ◦ Você pensou nesse erro antes de ler aqui? ◦ Problema fundamental  Novo comando  Ajuda precisa ser atualiza  Fácil de esquecer tal alteração  O programa compila e executa  O programador de manutenção pode muito bem acreditar que o trabalho esta terminado e liberar um programa que agora contem uma falha

45  Comandos alterados  Texto de ajuda deve ser modificado (acoplamento)  Mas nada no fonte do programa indica claramente essa dependência (implícito)  Classe bem projetada ◦ Evita acoplamento implícito  Seguindo a regra do projeto baseado na responsabilidade

46  Classe CommandWord ◦ Responsável pelas palavras de comando ◦ Deve ser responsável pelas impressão das palavras de comando ◦ Adicionar metodo showAll()  Classe Game ◦ printHelp()  Ao invés de imprimir texto fixo  Invoca um método de um objeto CommandWord para imprimir todas as palavras de comando

47  Game não tem referência a um objeto CommandWords ◦ Pode ser adicionado ◦ Diagrama de classe refletiria isso (Game teria relação com CommandWords)  Setas no diagrama de classe são uma primeira boa indicação do quanto um programa é fortemente acoplado. ◦ Mais setas, mais acoplamento ◦ Bons projetos  Diagramas com poucas setas

48  Game não ter referência a CommandWords é uma boa coisa  Isso não deve ser alterado  Ponto de vista de Game ◦ CommandWords é detalhe de implementação do Parser ◦ Parser  Retorna comandos  Decisão de usar um CommandWords para isso ou outra coisa é detalhe de implementação

49  Projeto Aprimorado  Adicionar em Game ◦ parser.showCommands() ◦ showCommands() em Parse  Delega responsabilidade ao objeto CommandWords

50  Projeto atual é bem melhor que o original  Contudo é possível aperfeiçoa-lo ainda mais  Característica de um bom projetista  Capacidade de pensar a frente  O que pode ser mudado?  O que permanecera inalterado durante toda a vida do programa?

51  Assumiu-se que o jogo será baseado em texto e um terminal de entrada e saída  Mas isso será sempre assim? ◦ Seria uma extensão interessante, a adição de uma GUI com menus, botões e imagens.  Nesse caso, nao imprimiria-se as informações no terminal  O metodo showAll () por exemplo, imprime as informações no console. Seria mais interessante deixar a classe CommandWords produzir a saída, porém a classe Game deve decidir como ela será apresentada ao usuário.

52  Observe que tais alterações não trás nenhum benefício agora, porém tal projeto aperfeiçoado pode trazer grandes benefícios no futuro.

53  Uma unidade de código deve ser sempre responsável por uma e somente uma tarefa. ◦ Princípio aplicado :  Classes  Métodos

54  Qualquer método deve ser responsável por somente uma tarefa bem definida  Exemplo de metodo coeso ◦ printWelcome() da classe Game  Ponto de vista Funcional  Todas as instruções que estão em printWelcome() poderiam ser colocadas diretamente no metodo play() de Game, evitando até uma chamada de método.  Métodos coesos ◦ Fácil de entender ◦ Fazer modificações  Métodos devem ser ◦ Razoavelmente curtos ◦ Seus nomes devem indicar claramente seus propósitos

55  A classe deve apresentar uma unica entidade bem definida no domínio do problema.  Outra extensão no projeto ◦ Adição de itens ao jogo ◦ Cada sala pode conter um item ◦ Item  Descrição  Peso (Determina se ele pode ser carregado ou nao)

56  Abordagem simples ◦ Adicionar dois campos a classe Room  itemDescription  itemWeight ◦ Tal abordagem não possui um bom grau de coesão  Room descreve tanto uma sala quanto um item  Outro problema e que isso vincula um item a uma sala, e isso pode não ser desejável  Projeto Aprimorado ◦ Criar uma classe separada para item (Item).  Descrição  Peso ◦ Room manteria uma referência a um objeto da classe Item

57  Benefícios reais de separar itens de salas ◦ Novos requisitos  Numero ilimitados de itens por sala  Com o projeto aprimorado isso e fácil  Criar multiplos objetos Item e armazenar em uma Collection na classe Room  Abordagem ingênua  Tal alteração seria quase impossível

58  Metodo printWelcome()  Classe Item ◦ Se uma alteração de alguma característica dos itens do jogo for necessária, um programador de manutenção sabe facilmente em qual classe começar examinar o código

59  Segunda grande vantagem de coesão é um potencial mais alto para reutilização  Por exemplo criando uma classe Item separada, pode-se criar múltiplos itens e assim utilizar o mesmo código de um único item.  A reutilização é um aspecto importante de coesão de método

60  Refatorando e testando

61  Acoplamento ◦ Descreve a interconectabilidade das classes. ◦ Objetivo  Acoplamento fraco  Cada classe e amplamente independente e comunica-se com outras classes por uma interface pequena e bem definida

62  Coesão ◦ Como uma unidade de código mapeia para uma tarefa lógica ou entidade. ◦ Objetivo  Sistema altamente coeso  Cada unidade de código é responsável por uma tarefa ou entidade bem definida.

63  Duplicação de Código ◦ Sinal de projeto ruim. ◦ Deve ser evitado.

64  Coesão de Método ◦ Responsável apenas por uma tarefa bem definida.

65  Coesão de Classe ◦ Representa uma entidade bem definida.

66  Encapsulamento ◦ Reduz o acoplamento e assim leva a um projeto aprimorado.

67  Projeto baseado na responsabilidade ◦ Processo de projetar classes atribuindo responsabilidades bem definidas a cada classe. ◦ Determina qual classe deve implementar qual parte de uma função da aplicação.

68  Minimizar as alterações ◦ Objetivos principais de um bom projeto  Localizar a alteração  Ao fazer alterações em uma classe, deve-se provocar o mínimo de efeitos em outras classes.

69  Refatoração ◦ Atividade de reestruturar um código existente para manter um bom projeto de classe quando a aplicação for modificada ou estendida.


Carregar ppt "Projeto de Classes.  Projeto baseado na responsabilidade  Acoplamento ◦ Explícito ◦ Implícito  Coesão ◦ Classes ◦ Métodos  Refatoração."

Apresentações semelhantes


Anúncios Google