quarta-feira, 17 de setembro de 2008

Coesão e Acoplamento

Aluno: Fernando Alves Michalak – 211010503

 

Maximizando a Coesão

  • Coesão é uma medida da diversidade dos "tópicos" abordados por uma entidade. 
  • Quanto menor a diversidade de assuntos abordados por uma entidade, maior a sua coesão.
  • Uma entidade bem focada em um determinado aspecto do sistema, é uma entidade bem coesa.
  • Sistemas onde os aspectos estão difusos são pouco flexíveis e dificultam extensões, modificações e reutilizações.
  • Cada classe deve ser o mais coesa quanto possível.
  • Cada classe deve representar apenas uma abstração.
  • Classes não coesas podem trazer, pelo menos, 3 problemas:
    1. a classe é mais difícil de entender
    2. está se supondo que as duas (ou mais) abstrações representadas pela classe tem sempre uma relação de 1 p/ 1 entre si.
    3. pode ser necessário especializar a classe em várias dimensões baseadas nas várias abstrações
  • Exemplo:
    • Uma classe para uma conta bancária que inclui informações sobre o correntista (nome, endereço, etc.)
    • Problema (2 acima): não permitirá contas conjuntas, se um correntista tem várias contas, os seus dados serão duplicados em cada conta o que gerará problemas de atualização e consistência.
    • Probema (3): especialização na dimensão do tipo de conta (corrente, poupança) e no tipo de correntista (pessoa física ou jurídica).
    • clip_image001 clip_image003
    • Solução: aumentar a coesão criando uma classe separada para o correntista
    • clip_image004
  • Regrinhas simples para maximizar coesão:
    • um atributo deve possuir um valor simples, não uma estrutura
    • um atributo deve descrever uma instância da classe (essa regra é violada pelo exemplo da figura clip_image001[1]
  • Outro exemplo:
    • Representação de vôos e seus respectivos aeroportos clip_image005
    • Problema: se o vôo é repetido todos os dias, estaremos duplicando os objetos que representam o intinerário todos os dias.
    • Isso ocorre pois estamos representando tando o intinerário quanto uma instância do vôo na mesma classe.
    • Solução: separar as duas abstrações
    • clip_image007
    • Flight Segment representa uma instância daquele vôo em um determinado dia, poderia incluir informações sobre a tripulação, por exemplo.
  • Os designs mais coesos descritos acima eliminam a redundância.
  • Redundância desperdiça espaço e dificulta a atualização dos dados.
  • Mas, muitas vezes, redundância pode melhorar o desempenho do sistema.

Minimizando o Acoplamento

  • Acoplamento é 
    • O quão "amarrado" uma parte do sistema é às outras partes. 
    • O quão dependente uma parte do sistema é das estruturas internas das outras partes do sistema.
    • Uma medida do quanto uma classe conhece do mundo à sua volta.
  • Se uma classe A conhece (e depende) da interface de uma classe B, e a interface da classe B é modificada, a classe A terá que ser modificada também.
  • Minimizando o acoplamento entre as classes (e objetos) de um sistema, nós facilitamos as modificações no sistema.
  • Há várias formas de acoplamento, entre elas:
    1. Acoplamento de Identidade
      • se um objeto guarda uma referência para outro, ele conhece a idêntidade do outro e, portanto, está acoplado a ele.
      • reduz-se acoplamento de identidade eliminando associações no diagrama de classes e implementando associações de forma uni-direcional.
      • note que em linguagens dinâmicas (Smalltalk, Self, Python, Lua) o acoplamento de identidade é mais leve do que em linguagens fortemente tipadas (Java, C++, C#)
    2. Acoplamento de Representação
      • ocorre quando um objeto referencia outro, i.e., acessa o outro
      • quanto mais específico o acesso (e.g., mexer nas variáveis públicas do outro objeto) maior o acoplamento.
      • usando um método "acessor" diminui um pouco o acoplamento (pois o método esconde a implementação do dado).
    3. Acoplamento de Subclasses
      • quando um objeto acessa uma subclasse usando a interface da subclasse ao invés de usar a interface da superclasse.
      • um cliente deve sempre usar uma referência para o tipo mais geral possível.
      • exemplo: em Java usar InputStream ao invés de usar FileInputStream.
      • clip_image009
      • clip_image010
      • Uma regra fundamental relacionada a esta é que devemos sempre programar para as interfaces e nunca para a implementação .
      • Assim, nos diagramas UML, as classes deveriam, sempre que possível, usar as <<interface>>s e não outras classes.
    4. Acoplamento de Herança
      • Uma subclasse é acoplada à sua superclasse através de acoplamento de herança.
      • É provavelmente o tipo de acoplamento mais forte.
      • Se manifesta fortemente em tempo de compilação. Mas também em tempo de execução.
      • O que uma classe herda em tempo de compilação não pode ser descartado em tempo de execução.
      • Isso difere de agregação, quando um objeto pode se desfazer de seus agregados em tempo de execução.
      • Exemplo: item de catálogo que é subclasse de item em estoque. E se a empresa decidir não guardar o item em estoque e encomendá-lo de terceiros toda vez que o item for encomendado?
      • clip_image011
      • clip_image013

Referência

Charles Richter. Designing Flexible Object-Oriented Systems with UML . Capítulo 4: Flexibility Guidelines for Class Diagrams. Macmillan Technical Publishing, 1999.

Nenhum comentário: