제이온

[Oggetti] Capitolo 2. Programmazione orientata agli oggetti

Creato: 2024-04-28

Creato: 2024-04-28 13:46

Sistema di prenotazione film


Esaminare i requisiti

  • Si desidera implementare un sistema di prenotazione film online.
  • Il film rappresenta le informazioni di base relative al film.
    • Come titolo, durata, informazioni sul prezzo, ecc.
  • La proiezione rappresenta l'evento in cui il pubblico guarda effettivamente il film.
    • Come data di proiezione, ora, numero d'ordine, ecc.
  • Le persone prenotano i film, ma in realtà dovrebbero prenotare un determinato proiezionedi un film, per essere precisi.
  • Condizioni di sconto
    • Disponibilità di sconti sul prezzo
    • Condizione d'ordine: utilizzo del numero d'ordine della proiezione per determinare la disponibilità di uno sconto
    • Condizione di periodo: utilizzo dell'ora di inizio della proiezione del film per determinare la disponibilità di uno sconto
  • Politica di sconto
    • Determinare la tariffa scontata
    • Politica di sconto in denaro: sconto di un determinato importo dalla tariffa di prenotazione
    • Politica di sconto percentuale: sconto di una determinata percentuale sul prezzo intero
  • Per ogni film è possibile assegnare una politica di sconto o non assegnarne alcuna, e le condizioni di sconto possono essere combinate con più condizioni di sconto.
  • Se una politica di sconto è applicata ma le condizioni di sconto non sono soddisfatte, o se non è applicata alcuna politica di sconto, la tariffa non viene scontata.


Verso la programmazione orientata agli oggetti

Collaborazione, oggetti, classi

  • L'orientamento agli oggetti è orientato agli oggetti.
    • Non bisogna preoccuparsi di quali attributi e metodi siano necessari per una classe dopo aver deciso la classe.
    • È necessario determinare quali oggetti hanno quali stati e comportamenti.
    • Gli oggetti devono essere visti non come entità indipendenti, ma come membri di una comunità collaborativa.


Struttura del programma che segue la struttura del dominio

  • Il dominio si riferisce all'area in cui l'utente utilizza il programma per risolvere un 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>

  • In generale, il nome di una classe deve essere lo stesso o almeno simile al nome del concetto di dominio corrispondente.
  • Anche la relazione tra le classi deve essere il più possibile simile alla relazione tra i concetti di dominio, in modo che la struttura del programma sia facile da capire e prevedere.


Implementazione della classe

  • La classe è divisa in interno ed esterno, e per progettare una buona classe, è necessario decidere quali parti rendere pubbliche e quali nascondere.
    • Gli attributi dell'oggetto sono bloccati come privati e i metodi necessari per modificare lo stato interno sono aperti come pubblici.
  • La separazione tra interno ed esterno della classe fornisce agli sviluppatori la libertà di implementazione garantendo l'autonomia dell'oggetto.


Oggetto autonomo

  • L'oggetto deve essere un'entità autonoma con stato e comportamento.
  • Il raggruppamento di dati e funzioni all'interno dell'oggetto è chiamato incapsulamento.
  • Il controllo di accesso riduce le interferenze esterne, consentendo all'oggetto di decidere autonomamente il proprio comportamento.
  • Il principio di separazione tra interfaccia e implementazione è un principio chiave che deve essere seguito nella programmazione orientata agli oggetti.
    • Interfaccia pubblica: parte accessibile dall'esterno
    • Implementazione: parte accessibile solo dall'interno


Libertà dello sviluppatore

  • Il ruolo dello sviluppatore è diviso in sviluppatore di classi e sviluppatore client.
    • Lo sviluppatore di classi aggiunge un nuovo tipo di dati
    • Lo sviluppatore client utilizza il tipo di dati aggiunto dallo sviluppatore di classi
  • Occultamento dell'implementazione
    • Lo sviluppatore di classi può nascondere l'implementazione interna fornendo solo le parti necessarie allo sviluppatore client.
    • Lo sviluppatore client deve conoscere solo l'interfaccia, quindi può ridurre la quantità di informazioni da gestire.


Comunità di oggetti collaborativi

  • Quando si rappresenta il denaro, è meglio impacchettarlo come un oggetto, come Money, invece di dichiarare semplicemente una variabile di tipo Long. Utilizzando oggetti, il significato viene trasmesso meglio e le elaborazioni ridondanti possono essere eseguite in un unico punto.
  • L'interazione tra gli oggetti per implementare una funzione del sistema è chiamata collaborazione.


Una breve storia sulla collaborazione

  • L'unico modo in cui un oggetto può interagire con un altro oggetto è inviare o ricevere messaggi.
  • Il proprio metodo per elaborare i messaggi ricevuti è chiamato metodo.
  • È importante distinguere tra messaggi e metodi, e questo è il punto di partenza del concetto di polimorfismo.


Calcolo della tariffa scontata

Iniziare la collaborazione per il calcolo della tariffa scontata

  • La classe Movie non contiene la logica dettagliata relativa alla politica di sconto e la delega all'interfaccia DiscountPolicy. È davvero importante utilizzare ereditarietà, polimorfismo e astrazione.


Politica di sconto e condizioni di sconto

<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>


Ereditarietà e polimorfismo

Dipendenza in fase di compilazione e dipendenza in fase di esecuzione

  • La dipendenza del codice e la dipendenza al momento dell'esecuzione possono essere diverse.
  • Più le dipendenze sono diverse, più il codice è difficile da capire, ma più il codice è flessibile ed estensibile.


Programmazione basata sulla differenza

  • L'ereditarietà consente di aggiungere facilmente e rapidamente nuove classi in base alle classi esistenti e di riutilizzare l'implementazione della classe padre.
  • Il metodo per creare una nuova classe aggiungendo solo le parti diverse dalla classe padre è chiamato programmazione basata sulla differenza.


Ereditarietà e interfaccia

  • L'ereditarietà fa sì che la classe figlia erediti tutte le interfacce fornite dalla classe padre.
  • L'interfaccia definisce un elenco di messaggi che un oggetto può comprendere.
  • Movie invia il messaggio calculateDiscountAmount a DiscountPolicy. Per Movie, non importa quale istanza di classe risponda, basta che risponda correttamente.
  • Pertanto, sia AmountDiscountPolicy che PercentDiscountPolicy possono collaborare con Movie al posto di DiscountPolicy.
  • Questo tipo di sostituzione di una classe figlia con una classe padre è chiamato upcasting. Questo perché sembra che la classe figlia venga automaticamente convertita nel tipo della classe padre.


Polimorfismo

  • Il polimorfismo è la capacità di rispondere in modo diverso a seconda del tipo di oggetto quando si riceve lo stesso messaggio.
    • Movie invia lo stesso messaggio, ma il metodo effettivamente eseguito dipende dalla classe dell'oggetto che riceve il messaggio.
  • Il polimorfismo si basa sul fatto che la dipendenza in fase di compilazione e la dipendenza in fase di esecuzione del programma possono essere diverse.
  • Poiché il polimorfismo determina il metodo da eseguire al momento dell'esecuzione, è chiamato binding ritardato o binding dinamico.


Interfaccia e polimorfismo

  • Se si desidera condividere solo l'interfaccia e non è necessario condividere l'implementazione, è possibile utilizzare un'interfaccia invece di una classe astratta.


Astrazione e flessibilità

Il potere dell'astrazione

  • Vantaggi dell'astrazione
    • Esaminando solo il livello di astrazione, è possibile descrivere la politica dei requisiti a un livello elevato.
    • Il design diventa più flessibile.


Design flessibile

  • L'astrazione impedisce che il design sia legato a situazioni specifiche, consentendo di creare un design flessibile.


Compromesso tra classe astratta e interfaccia


  • Attualmente, NoneDiscountPolicy non è in realtà necessario perché, nel metodo calculateDiscountAmount() di DiscountPolicy, se non ci sono condizioni di sconto, viene restituito 0, quindi non ci sono problemi. Tuttavia, è stato aggiunto perché l'utente deve fornire una politica Nessuno come argomento di Movie.
  • Pertanto, la classe NoneDiscountPolicy è confusa e, modificandola come mostrato di seguito, è più facile da capire.



  • Come mostrato sopra, DiscountPolicy viene astratto come un'interfaccia e viene diviso in NoneDiscountPolicy, che è la sua implementazione, e DefaultDiscountPolicy, che rappresenta una politica di sconto generale.

<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>

  • Si potrebbe pensare che aggiungere un'interfaccia solo per NoneDiscountPolicy comporti una complessità eccessiva rispetto al guadagno di efficienza.
  • È necessario essere consapevoli del fatto che tutto ciò che riguarda l'implementazione può essere oggetto di un compromesso e progettare di conseguenza. In altre parole, ogni riga di codice deve avere una ragione valida.


Riutilizzo del codice

  • L'ereditarietà può essere utilizzata per riutilizzare il codice.
  • Tuttavia, per il riutilizzo del codice, è preferibile utilizzare la composizione rispetto all'ereditarietà.
  • Nel codice corrente, il modo in cui Movie riutilizza il codice di DiscountPolicy è proprio la composizione.
  • Se Movie fosse la classe padre e fosse suddivisa in AmountDiscountMovie e PercentDiscountMovie, si potrebbe dire che viene utilizzata l'ereditarietà.


Ereditarietà

  • Svantaggi dell'ereditarietà
    • Viola l'incapsulamento.
      • È necessario conoscere la struttura interna della classe padre.
      • È più probabile che la classe figlia debba essere modificata quando la classe padre viene modificata.
    • Rende il design meno flessibile.
      • La relazione tra la classe padre e la classe figlia viene decisa in fase di compilazione.
      • Non è possibile modificare il tipo di oggetto in fase di esecuzione.
      • Tuttavia, la composizione consente di sostituire le istanze in fase di esecuzione tramite un metodo come changeDiscountPolicy() lato oggetto che utilizza l'oggetto.


Composizione

  • Il metodo per riutilizzare il codice solo tramite messaggi definiti nell'interfaccia è chiamato composizione.
  • Consente di implementare l'incapsulamento e di mantenere un accoppiamento lasco.
  • Quando si riutilizza un'interfaccia per il polimorfismo, è necessario utilizzare una combinazione di ereditarietà e composizione.
    • Ad esempio, l'interfaccia DiscountPolicy deve utilizzare l'ereditarietà per implementare le sue sottoclassi.


Fonti

  • Oggetto

Commenti0