Sistema de Reserva de Filmes
Analisando os Requisitos
- Pretende-se implementar um sistema de reserva de filmes online.
- O filme representa as informações básicas sobre o filme.
- Como título, duração e informações de preço.
- A exibição representa o evento real em que o público assiste ao filme.
- Como data de exibição, hora e número de ordem.
- As pessoas reservam filmes, mas na verdade, seria mais correto dizer que elas reservam uma determinada exibiçãode um filme.
- Condições de desconto
- Se o preço será ou não descontado.
- Condição de ordem: usar o número de ordem da exibição para determinar se haverá desconto.
- Condição de período: usar a hora de início da exibição do filme para determinar se haverá desconto.
- Política de desconto
- Determinar o valor do desconto.
- Política de desconto em valor: descontar um valor fixo da taxa de reserva.
- Política de desconto percentual: descontar uma porcentagem do preço original.
- Cada filme pode ter uma política de desconto atribuída a ele ou não ter nenhuma, e as condições de desconto podem ser combinadas.
- Se a política de desconto estiver aplicada, mas as condições de desconto não forem atendidas, ou se a política de desconto não estiver aplicada, a taxa não será descontada.
Em direção à Programação Orientada a Objetos
Cooperação, Objetos e Classes
- Orientação a objetos é orientar-se por objetos.
- Não devemos pensar em quais atributos e métodos uma classe precisa ter depois de decidir sobre a classe.
- Devemos decidir quais objetos têm quais estados e comportamentos.
- Os objetos devem ser vistos não como entidades independentes, mas como membros de uma comunidade que coopera.
Estrutura do programa que segue a estrutura do domínio
- Domínio refere-se à área em que o usuário usa o programa para resolver um problema.
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fe7d22a03-4a24-40e9-8068-bd03b9fd816b%2FUntitled.png?table=block&id=3f1931fc-8ef9-470a-8189-3727146638f6&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/438;" width="2000" height="438"></span>
- Em geral, o nome da classe deve ser o mesmo ou pelo menos semelhante ao nome do conceito de domínio correspondente.
- O relacionamento entre as classes também deve ser o mais semelhante possível ao relacionamento entre os conceitos de domínio, tornando a estrutura do programa mais fácil de entender e prever.
Implementando Classes
- Uma classe é dividida em interno e externo, e para projetar uma boa classe, você precisa decidir quais partes tornar públicas e quais partes ocultar.
- Os atributos de um objeto são ocultados como privados, e os métodos necessários para modificar o estado interno são abertos como públicos.
- Ao distinguir entre o interior e o exterior de uma classe, garante-se a autonomia do objeto, fornecendo ao programador a liberdade de implementação.
Objeto Autônomo
- Um objeto deve ser um objeto autônomo com estado e comportamento.
- O ato de agrupar dados e funções dentro de um objeto é chamado de encapsulamento.
- O controle de acesso deve ser usado para reduzir a interferência externa, permitindo que o objeto decida seu próprio comportamento.
- O princípio de separação entre interface e implementação é um princípio importante a ser seguido na programação orientada a objetos.
- Interface pública: parte acessível de fora.
- Implementação: parte acessível apenas de dentro.
Liberdade do Programador
- O papel do programador é dividido em programador de classe e programador cliente.
- O programador da classe adiciona novos tipos de dados.
- O programador cliente usa os tipos de dados adicionados pelo programador da classe.
- Ocultar implementação
- O programador da classe pode ocultar a implementação interna fornecendo apenas as partes necessárias ao programador cliente.
- Como o programador cliente só precisa saber a interface, a quantidade de conhecimento que ele precisa ter é reduzida.
Comunidade de objetos cooperantes
- Ao representar dinheiro, é melhor encapsulá-lo em um objeto, como Money, em vez de simplesmente declarar uma variável do tipo Long. Ao usar objetos, a comunicação é melhor e operações redundantes podem ser realizadas em um único local.
- A interação entre objetos para implementar alguma função do sistema é chamada de cooperação.
Uma breve história sobre cooperação
- A única maneira de um objeto interagir com outro objeto é enviando ou recebendo mensagens.
- O método é a maneira como ele próprio processa a mensagem recebida.
- É importante distinguir entre mensagem e método, e é daí que surge o conceito de polimorfismo.
Calculando a Taxa de Desconto
Iniciando a cooperação para calcular a taxa de desconto
- A classe Movie não contém a lógica detalhada da política de desconto e a delegou para a interface DiscountPolicy. O uso de herança, polimorfismo e abstração é realmente importante.
Política de desconto e condição de desconto
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F7b9b27a5-0dac-4ba7-9552-05b7f8fbdecd%2FUntitled.png?table=block&id=3264f189-6e12-4a55-94d2-75b851320c7a&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/535;" width="2000" height="535"></span>
Herança e Polimorfismo
Dependência em tempo de compilação e dependência em tempo de execução
- A dependência do código e a dependência do momento de execução podem ser diferentes.
- Quanto mais diferentes forem as dependências, mais difícil será entender o código, mas o código se tornará mais flexível e extensível.
Programação por diferença
- A herança permite que novas classes sejam adicionadas facilmente e rapidamente com base em classes existentes, e a implementação da classe pai pode ser reutilizada.
- O método de criar uma nova classe adicionando apenas as partes diferentes da classe pai é chamado de programação por diferença.
Herança e Interface
- A herança faz com que a classe filha herde todas as interfaces fornecidas pela classe pai.
- A interface define uma lista de mensagens que um objeto pode entender.
- Movie está enviando uma mensagem calculateDiscountAmount para DiscountPolicy. Do ponto de vista de Movie, não importa qual instância de classe responde, desde que responda com sucesso.
- Portanto, tanto AmountDiscountPolicy quanto PercentDiscountPolicy podem cooperar com Movie em vez de DiscountPolicy.
- Essa capacidade da classe filha substituir a classe pai é chamada de upcasting. Isso ocorre porque parece que a classe filha é automaticamente convertida para o tipo da classe pai.
Polimorfismo
- Polimorfismo é a capacidade de responder de forma diferente dependendo do tipo de objeto quando a mesma mensagem é recebida.
- Movie envia a mesma mensagem, mas qual método é realmente executado depende de qual classe o objeto que recebe a mensagem é.
- O polimorfismo é baseado no fato de que a dependência em tempo de compilação e a dependência em tempo de execução de um programa podem ser diferentes.
- Como o polimorfismo determina qual método será executado em tempo de execução, ele é chamado de vinculação tardia ou vinculação dinâmica.
Interface e Polimorfismo
- Se você não precisa compartilhar a implementação e deseja compartilhar apenas a interface, pode usar uma interface em vez de uma classe abstrata.
Abstração e Flexibilidade
O poder da abstração
- Vantagens da abstração
- Se você olhar apenas para a hierarquia de abstração, poderá descrever a política de requisitos em um nível alto.
- O design fica mais flexível.
Design flexível
- A abstração evita que o design seja vinculado a situações específicas, permitindo que um design flexível seja criado.
Trade-off entre classe abstrata e interface
- Atualmente, NoneDiscountPolicy não é realmente necessário, pois se não houver condição de desconto no método calculateDiscountAmount() de DiscountPolicy, 0 será retornado, então não há problema. No entanto, o usuário precisa inserir uma política None sem condição de desconto como argumento para Movie, então ela foi adicionada.
- Portanto, a classe NoneDiscountPolicy é confusa do ponto de vista do usuário, então se ela for modificada como abaixo, será mais fácil de entender.
- Como mostrado acima, a ideia é abstrair DiscountPolicy como uma interface e dividi-la em NoneDiscountPolicy, que é sua implementação, e DefaultDiscountPolicy, que representa uma política de desconto geral.
<span class="image-inline ck-widget" contenteditable="false"><img src="https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F712983a9-3937-4265-82fe-66a144c44a0f%2FUntitled.png?table=block&id=f5ca651c-d03c-4a6c-97e9-7443ee5649a0&spaceId=b453bd85-cb15-44b5-bf2e-580aeda8074e&width=2000&userId=80352c12-65a4-4562-9a36-2179ed0dfffb&cache=v2" alt="Untitled" style="aspect-ratio:2000/886;" width="2000" height="886"></span>
- Você pode pensar que adicionar uma interface apenas para NoneDiscountPolicy é ineficaz em relação ao aumento da complexidade.
- Você deve estar ciente de que tudo relacionado à implementação pode ser alvo de trade-off e projetar com base nisso. Ou seja, todo código que você escreve deve ter uma razão lógica.
Reutilização de código
- A herança pode ser usada para reutilizar código.
- No entanto, para a reutilização de código, é melhor usar composição em vez de herança.
- No código atual, a maneira como Movie reutiliza o código de DiscountPolicy é através da composição.
- Se Movie fosse a classe pai e fosse dividida em AmountDiscountMovie e PercentDiscountMovie, seria considerado o uso de herança.
Herança
- Desvantagens da herança
- Viola o encapsulamento.
- Você precisa saber a estrutura interna da classe pai.
- É mais provável que a classe filha também precise ser modificada quando a classe pai for modificada.
- Torna o design menos flexível.
- O relacionamento entre a classe pai e a classe filha é determinado em tempo de compilação.
- É impossível alterar o tipo de objeto em tempo de execução.
- No entanto, com a composição, o lado que usa pode substituir a instância em tempo de execução através de métodos como changeDiscountPolicy().
- Viola o encapsulamento.
Composição
- O método de reutilizar código apenas por meio de mensagens definidas na interface é chamado de composição.
- Pode implementar o encapsulamento e manter um acoplamento fraco.
- Quando uma interface é reutilizada para polimorfismo, herança e composição devem ser combinadas.
- Por exemplo, a interface DiscountPolicy precisa usar herança para implementar suas classes filhas.
Fontes
- Objetos
Comentários0