제이온

[Objetos] Capítulo 1. Objeto, Design

  • Idioma de escrita: Coreana
  • País de referência: Todos os paísescountry-flag
  • TI

Criado: 2024-04-28

Criado: 2024-04-28 13:45

Introdução

Robert L. Glass argumentou que a prática vem antes da teoria. O desenvolvimento de software, em particular, é um campo onde a prática lidera a teoria, e os desenvolvedores aprendem mais quando estão envolvidos na criação de código concreto, 'sujando as mãos'. Portanto, vamos deixar a teoria e os conceitos de lado por enquanto e dar uma olhada em um programa simples.


Implementando um aplicativo de venda de ingressos

  • Estamos planejando um pequeno evento para promover um pequeno teatro.
    • Conteúdo do evento: enviar convites para assistir a uma apresentação gratuitamente para espectadores selecionados por sorteio.
  • Precisamos separar os espectadores que ganharam o evento daqueles que não ganharam.
    • Espectadores que ganharam o evento: trocar o convite por um ingresso.
    • Espectadores que não ganharam o evento: comprar o ingresso com dinheiro.



Qual é o problema?

Robert Martin descreve três funções que um módulo de software (independentemente do tamanho, como uma classe, pacote ou biblioteca, qualquer elemento que compõe um programa) deve ter.


  • Funciona corretamente durante a execução.
  • Existe para ser modificado.
    • Deve ser possível fazer alterações com um mínimo de esforço.
  • Se comunica com quem lê o código.
    • Deve ser fácil para os desenvolvedores ler e entender.


O aplicativo de venda de ingressos anterior atende à primeira restrição, funcionando corretamente, mas não atende aos objetivos de facilidade de modificação e comunicação.


Código que foge às expectativas

Vamos analisar o motivo pelo qual ele não atende ao objetivo de comunicação.


  • O que o método enter() da classe Theater faz?
    • O teatro abre a bolsa do espectador para ver se há um convite dentro.
    • Se houver um convite na bolsa, o teatro instrui o vendedor a transferir o ingresso armazenado na bilheteria para a bolsa do espectador.
    • Se não houver um convite na bolsa, o teatro pega o dinheiro da bolsa do espectador, compra um ingresso e o coloca na bolsa.
  • Do ponto de vista do espectador, ele precisa assistir a um terceiro (o teatro) mexendo em sua bolsa, pegando seu dinheiro e colocando um ingresso.
  • Do ponto de vista do vendedor, ele precisa assistir a um terceiro (o teatro) manipulando os ingressos e dinheiro na bilheteria sem permissão.
  • Código compreensível significa código que não diverge muito do que esperamos, e o teatro acima diverge do que esperamos.
    • O espectador deve pegar o dinheiro de sua bolsa e pagar ao vendedor para receber o ingresso.
    • O vendedor deve pegar o ingresso da bilheteria e entregá-lo ao espectador, recebendo o dinheiro do espectador e guardando-o na bilheteria.
  • Além disso, para entender o método enter(), é necessário lembrar de vários detalhes.
    • Audience possui Bag.
    • Bag contém dinheiro e ingressos.
    • TicketSeller vende ingressos em TicketOffice, e TicketOffice armazena dinheiro e ingressos.


Código vulnerável a alterações

O método enter() assume duas condições.

  • O espectador sempre carrega uma bolsa para guardar dinheiro e convites.
  • O vendedor vende ingressos apenas na bilheteria.


E se as seguintes situações acontecerem?

  • O espectador pode não ter uma bolsa.
  • O espectador pode usar um cartão de crédito em vez de dinheiro.
  • O vendedor pode vender ingressos fora da bilheteria.


Por exemplo, para atender ao primeiro requisito, precisamos remover o objeto Bag de Audience e modificar o método enter() da classe Theater relacionado a ele. Isso ocorre porque a classe Theater depende muito do fato de que o espectador carrega uma bolsa e o vendedor vende ingressos apenas na bilheteria. Se qualquer um desses detalhes mudar, precisamos modificar a classe correspondente e as classes dependentes (por exemplo, Theater).


Este é um problema relacionado à dependência entre objetos, e a dependência implica impacto na alteração. No entanto, o design orientado a objetos tem como objetivo construir uma comunidade de objetos que cooperam enquanto dependem uns dos outros, então, em vez de remover a dependência sem pensar, precisamos manter apenas a dependência mínima necessáriae remover dependências desnecessárias.


Quando a dependência entre objetos é muito alta, dizemos que o acoplamentoé alto, e quanto maior o acoplamento entre dois objetos, maior a probabilidade de eles mudarem juntos. Portanto, o objetivo do design é reduzir o acoplamento entre objetos para criar um design que seja fácil de modificar.


Melhorando o design

O Theater não precisa saber que o espectador tem uma bolsa ou que o vendedor vende ingressos na bilheteria. O Theater simplesmente quer que o espectador entre no teatro. Portanto, precisamos tornar o espectador e o vendedor entidades autônomas, onde o espectador gerencia seu próprio dinheiro e convite, e o vendedor gerencia seus próprios ingressos e preços de venda na bilheteria.


Aumentar a autonomia

Um objeto que realiza apenas tarefas estreitamente relacionadas e delega tarefas não relacionadas a outros objetos é considerado altamente coeso. Criar objetos autônomos que gerenciam seus próprios dados reduz o acoplamento e aumenta a coesão.


Programação Procedural e Orientada a Objetos

  • Programação Procedural
    • O método enter() de Theater é um processo, e Audience, TicketSeller, Bag e TicketOffice são dados.
    • A maneira como os processos e dados são colocados em módulos separados é chamada de programação procedural.
    • Há muito código que vai contra nossa intuição. (por exemplo, o espectador gerencia seu próprio dinheiro e convite).
    • É difícil restringir o impacto das alterações nos dados.
    • A responsabilidade é gerenciada de forma centralizada. (Theater gerencia tudo)
  • Programação Orientada a Objetos
    • A maneira como os dados e processos são colocados no mesmo módulo é chamada de programação orientada a objetos.
    • Podemos escrever código que corresponde à nossa intuição.
    • O impacto das alterações nos dados pode ser efetivamente restringido por meio de encapsulamento.
    • Cada objeto é responsável por si mesmo.


Pode ser ainda melhor

  • A classe Bag da classe Audience ainda é uma entidade passiva que é controlada pela classe Audience, portanto, precisamos tornar a classe Bag uma entidade autônoma.
  • O TicketOffice da classe TicketSeller também é controlado pela classe TicketSeller. Precisamos tornar o TicketOffice uma entidade autônoma.
    • No entanto, após a alteração, o TicketOffice teve um acoplamento adicional com Audience.
    • Como no design, devemos considerar cuidadosamente os trade-offs. Neste caso, para reduzir o acoplamento com Audience, podemos concordar em tornar o TicketOffice uma entidade ligeiramente passiva.



Isso é mentira!

  • Na realidade, mesmo que algo seja passivo, quando entra no mundo orientado a objetos, ele se torna uma entidade ativa e autônoma.
  • É útil usar a personificação e pensar em entidades passivas como se estivessem rindo, falando e brigando.


Design Orientado a Objetos

Por que o design é necessário?

  • Design é sobre como organizar o código.
  • Um bom design é aquele que atende totalmente às necessidades de hoje e permite acomodar mudanças futuras sem problemas.


Design Orientado a Objetos

  • Código modificável é código fácil de entender.
  • O paradigma orientado a objetos nos ajuda a escrever código da mesma forma que vemos o mundo.
  • Os objetos são entidades autônomas que são responsáveis por seus próprios dados.
  • Um bom design orientado a objetos é um design que gerencia adequadamente as dependências entre objetos que cooperam.


Fontes

  • Objetos

Comentários0