MAC 441/5714 - Programação Orientada a Objetos
Aula de hoje: Aumentando a Flexibilidade
- Na vida real, sistemas de software tendem a sobreviver vários anos.
- Mesmo sistemas desenvolvidos para ter vida curta, acabam vivendo muito mais tempo do que o esperado.
- No entanto,
- os requisitos tendem a variar ao longo da vida do sistema,
- os sistemas são estendidos de diferentes formas para acrescentar novas funcionalidades não antecipadas e
- partes de um sistema são utilizadas em outros sistemas (reutilização).
- Portanto, os sistemas devem ter flexibilidade para que possam ser
- adaptados a diferentes contextos e
- estendidos em diferentes direções.
- Mas é preciso cuidado. Lição de Programação eXtrema:
- Não antecipe necessidades, pois elas podem não aparecer.
- Não incorpore flexibilidade desnecessária.
- Possível abordagem para enfrentar essa dicotomia:
- A arquitetura do sistema deve ser sempre a mais simples possível.
- Less is more. Frase do famoso arquiteto Mies van der Rohe.
- Outra forma importante de incorporar flexibilidade sem aumentar a complexidade:
- maximizar a coesão
- minimizar o acoplamento
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 possível.
- Cada classe deve representar apenas uma abstração.
- Classes não coesas podem trazer, pelo menos, 3 problemas:
- a classe é mais difícil de entender
- está se supondo que as duas (ou mais) abstrações
representadas pela classe tem sempre uma relação de 1 para 1
entre si (ex. Classe Casal).
- 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.
- Problema (3): especialização na dimensão do tipo de conta (corrente, poupança) e no tipo de correntista (pessoa física ou
jurídica).
- FIGURA 4.1 e 4.2
- Solução: aumentar a coesão criando uma classe separada para o correntista
- FIGURA 4.4
- 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 4.1) (dados
pessoais na classe Account)
- Outro exemplo:
- Representação de vôos e seus respectivos aeroportos
- FIGURA 4.6
- 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 tanto o intinerário quanto uma instância do vôo na mesma classe.
- Solução: separar as duas abstrações
- FIGURA 4.7
- 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:
- Acoplamento de Identidade
- se um objeto guarda uma referência para outro, ele conhece a identidade 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, Ruby) o acoplamento de identidade é mais leve do que em linguagens fortemente tipadas (Java, C++, C#)
- Acoplamento de Representação
- ocorre quando um objeto referencia outro, i.e., acessa o outro
- quanto mais específico o acesso (p.ex., mexer nas variáveis públicas do outro objeto) maior o acoplamento.
- usando um método "de acesso" diminui um pouco o acoplamento (pois o método esconde a implementação do dado).
- 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.
- FIGURA 4.8
- FIGURA 4.9
- 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.
- 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?
- FIGURA 4.13
- FIGURA 4.14
Referência
Charles Richter. Designing Flexible Object-Oriented Systems with UML. Capítulo 4: Flexibility Guidelines for Class Diagrams. Macmillan Technical
Publishing, 1999.
Próxima Aula
Aula Anterior
Página de MAC 441/5714
Página do Fabio
Página do DCC