![translation](https://cdn.durumis.com/common/trans.png)
Questo è un post tradotto da IA.
[Oggetto] Capitolo 2. Programmazione orientata agli oggetti
- Lingua di scrittura: Coreana
- •
-
Paese di riferimento: Tutti i paesi
- •
- Tecnologia dell'informazione
Seleziona la lingua
Testo riassunto dall'intelligenza artificiale durumis
- Spiega l'approccio alla programmazione orientata agli oggetti per implementare un sistema di prenotazione di biglietti cinematografici, introducendo i concetti di collaborazione, oggetti e classi e sottolineando la struttura del programma che segue la struttura del dominio.
- In particolare, viene presentato un metodo per ridurre l'interferenza esterna attraverso l'autonomia degli oggetti e l'incapsulamento, e per garantire la libertà del programmatore separando l'interfaccia dall'implementazione.
- Inoltre, vengono illustrate le tecniche di scrittura di codice flessibile ed espandibile utilizzando la collaborazione, l'ereditarietà e il polimorfismo per il calcolo dei prezzi scontati, e viene sottolineata l'importanza dell'astrazione e i vantaggi della composizione per la riutilizzabilità del codice.
Sistema di prenotazione dei biglietti del cinema
Esame dei requisiti
- Vogliamo implementare un sistema di prenotazione biglietti online per il cinema.
- Un film rappresenta le informazioni di base su un film.
- Titolo, durata, informazioni sul prezzo, ecc.
- Una proiezione rappresenta l'evento in cui il pubblico effettivamente guarda un film.
- Data, ora, numero di proiezione, ecc.
- Le persone prenotano i biglietti per un film, ma in realtà dovrebbero prenotare una proiezionedi un film.
- Condizioni di sconto
- Se è disponibile uno sconto sul prezzo.
- Condizione di sequenza: utilizzare il numero di proiezione per determinare se è disponibile uno sconto.
- Condizione temporale: utilizzare l'orario di inizio della proiezione del film per determinare se è disponibile uno sconto.
- Politiche di sconto
- Determinare il costo scontato.
- Politica di sconto in base all'importo: sconto di un importo fisso sulla tariffa di prenotazione.
- Politica di sconto in base alla percentuale: sconto di una percentuale fissa del prezzo intero.
- È possibile assegnare una politica di sconto a ciascun film o non assegnarne alcuna, ed è possibile combinare più condizioni di sconto.
- Se è applicata una politica di sconto, ma non sono soddisfatte le condizioni di sconto, o se non è applicata alcuna politica di sconto, il prezzo non è scontato.
Verso la programmazione orientata agli oggetti
Collaborazione, oggetti, classi
- La programmazione orientata agli oggetti è orientata agli oggetti.
- Non dovremmo preoccuparci di quali attributi e metodi siano necessari per una classe dopo aver deciso la classe.
- Dobbiamo decidere quali oggetti abbiano quali stati e comportamenti.
- Gli oggetti non dovrebbero essere visti come entità indipendenti, ma come membri di una comunità collaborativa.
Struttura del programma che segue la struttura del dominio
- Il dominio è il campo in cui gli utenti utilizzano il programma per risolvere un problema.
- In generale, il nome delle classi dovrebbe corrispondere o almeno essere simile al nome del concetto di dominio corrispondente.
- Anche la relazione tra le classi dovrebbe essere il più possibile simile alla relazione stabilita tra i concetti di dominio, in modo che la struttura del programma sia facile da capire e prevedere.
Implementare le classi
- Le classi sono divise in interno ed esterno e, per progettare una classe eccellente, dobbiamo decidere quali parti rendere pubbliche e quali nascondere.
- Gli attributi di un oggetto sono bloccati come privati e i metodi necessari per modificare lo stato interno sono aperti come pubblici.
- Separando l'interno dall'esterno di una classe, possiamo garantire l'autonomia degli oggetti, offrendo ai programmatori la libertà di implementazione.
Oggetti autonomi
- Gli oggetti dovrebbero essere oggetti autonomi con stati e comportamenti.
- Il raggruppamento di dati e funzionalità all'interno di un oggetto è chiamato incapsulamento.
- Il controllo di accesso dovrebbe essere utilizzato per ridurre l'interferenza esterna, in modo che gli oggetti possano decidere le proprie azioni.
- Il principio di separazione tra interfaccia e implementazione è un principio chiave da seguire nella programmazione orientata agli oggetti.
- Interfaccia pubblica: parti accessibili dall'esterno
- Implementazione: parti accessibili solo internamente
Libertà del programmatore
- Il ruolo dei programmatori è diviso in creatori di classi e programmatori client.
- Creatori di classi: aggiungono nuovi tipi di dati
- Programmatori client: utilizzano i tipi di dati aggiunti dai creatori di classi
- Nascondere l'implementazione
- I creatori di classi possono nascondere l'implementazione interna fornendo solo le parti necessarie ai programmatori client.
- I programmatori client devono conoscere solo l'interfaccia, riducendo così la quantità di conoscenza.
Una comunità di oggetti collaborativi
- Quando si rappresenta il denaro, è meglio impacchettarlo come un oggetto, come Money, anziché semplicemente dichiarare una variabile di tipo Long. Questo perché l'utilizzo di oggetti consente una migliore comunicazione del significato e consente di eseguire le operazioni ripetute in un unico punto.
- L'interazione tra oggetti per implementare una funzionalità del sistema è chiamata collaborazione.
Una breve storia di collaborazione
- L'unico modo in cui un oggetto può interagire con un altro oggetto è inviando o ricevendo messaggi.
- I metodi sono i modi unici che un oggetto ha per elaborare i messaggi ricevuti.
- È importante distinguere tra messaggi e metodi, da qui deriva il concetto di polimorfismo.
Calcolo del prezzo scontato
Avviare la collaborazione per calcolare il prezzo scontato
- La classe Movie non contiene alcuna logica dettagliata relativa alle politiche di sconto e delega all'interfaccia DiscountPolicy. L'ereditarietà, il polimorfismo e l'astrazione sono essenziali.
Politica di sconto e condizioni di sconto
Ereditarietà e polimorfismo
Dipendenza in fase di compilazione e dipendenza in fase di esecuzione
- Le dipendenze del codice possono essere diverse dalle dipendenze in fase di esecuzione.
- Più queste dipendenze sono diverse, più il codice è difficile da capire, ma più è flessibile ed estendibile.
Programmazione per differenza
- L'ereditarietà consente di aggiungere nuove classi in modo semplice e veloce basandosi su 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 per differenza.
Ereditarietà e interfacce
- L'ereditarietà fa sì che le classi figlie ereditino tutte le interfacce fornite dalle classi padre.
- Le interfacce definiscono un elenco di messaggi che un oggetto può comprendere.
public class Movie {
public Money calculateMovieFee(Screening screening) {
return fee.minus(discountPolicy.calculateDiscountAmount(screening));
}
- Movie invia il messaggio calculateDiscountAmount a DiscountPolicy. Per Movie, non importa quale istanza di classe risponda, finché fornisce una risposta valida.
- Pertanto, sia AmountDiscountPolicy che PercentDiscountPolicy possono collaborare con Movie al posto di DiscountPolicy.
- Questo processo, in cui una classe figlio sostituisce una classe padre, è chiamato upcasting. Questo perché sembra che la classe figlio venga automaticamente convertita in un tipo di 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 le dipendenze di compilazione e di esecuzione di un programma possono essere diverse.
- Il polimorfismo determina il metodo da eseguire in fase di esecuzione, quindi è anche chiamato binding ritardato o binding dinamico.
Interfacce e polimorfismo
- Se vogliamo condividere solo l'interfaccia e non l'implementazione, possiamo usare un'interfaccia invece di una classe astratta.
Astrazione e flessibilità
Il potere dell'astrazione
- Vantaggi dell'astrazione
- Se esaminiamo solo il livello di astrazione, possiamo descrivere le politiche dei requisiti a un livello più alto.
- La progettazione diventa più flessibile.
Progettazione flessibile
- L'astrazione impedisce che la progettazione sia vincolata a situazioni specifiche, quindi è possibile creare una progettazione flessibile.
Classi astratte e trade-off dell'interfaccia
public abstract class DiscountPolicy {
private List conditions;
public DiscountPolicy(DiscountCondition... conditions) {
this.conditions = Arrays.asList(conditions);
}
public Money calculateDiscountAmount(Screening screening) {
for (DiscountCondition condition : conditions) {
if (condition.isSatisfiedBy(screening)) {
return getDiscountAmount(screening);
}
}
return Money.ZERO;
}
abstract protected Money getDiscountAmount(Screening screening);
}
public class NoneDiscountPolicy extends DiscountPolicy {
@Override
protected Money getDiscountAmount(Screening screening) {
return Money.ZERO;
}
- Attualmente, NoneDiscountPolicy è in realtà superflua perché, se non ci sono condizioni di sconto, il metodo calculateDiscountAmount() di DiscountPolicy restituisce 0, quindi non c'è problema. Tuttavia, dall'utilizzo di utenti, è necessario inserire la politica di sconto None senza sconto come argomento di Movie, quindi è stato aggiunto.
- Pertanto, per una migliore comprensione, è possibile modificarlo come segue.
public interface DiscountPolicy {
Money calculdateDiscountAmount(Screening screening);
}
public abstract class DefaultDiscountPolicy implements DiscountPolicy {
private List conditions;
public DefaultDiscountPolicy(DiscountCondition... conditions) {
this.conditions = Arrays.asList(conditions);
}
public Money calculateDiscountAmount(Screening screening) {
for (DiscountCondition condition : conditions) {
if (condition.isSatisfiedBy(screening)) {
return getDiscountAmount(screening);
}
}
return Money.ZERO;
}
abstract protected Money getDiscountAmount(Screening screening);
}
public class NoneDiscountPolicy implements DiscountPolicy {
@Override
public Money calculateDiscountAmount(Screening screening) {
return Money.ZERO;
}
}
public class PercentDiscountPolicy extends DefaultDiscountPolicy {
private double percent;
public PercentDiscountPolicy(double percent, DiscountCondition... conditions) {
super(conditions);
this.percent = percent;
}
@Override
protected Money getDiscountAmount(Screening screening) {
return screening.getMovieFee().times(percent);
}
}
public class AmountDiscountPolicy extends DefaultDiscountPolicy {
private Money discountAmount;
public AmountDiscountPolicy(Money discountAmount, DiscountCondition... conditions) {
super(conditions);
this.discountAmount = discountAmount;
}
@Override
protected Money getDiscountAmount(Screening screening) {
return discountAmount;
}
- In questo modo, DiscountPolicy viene astratto come interfaccia e viene diviso in NoneDiscountPolicy, che è un'implementazione, e DefaultDiscountPolicy, che rappresenta una politica di sconto generale.
- Si potrebbe pensare che l'aggiunta di un'interfaccia solo per NoneDiscountPolicy sia inefficace rispetto all'aumento della complessità.
- È necessario riconoscere che tutto ciò che riguarda l'implementazione è oggetto di trade-off e progettare di conseguenza. In altre parole, ogni riga di codice deve avere una motivazione valida.
Riutilizzo del codice
- L'ereditarietà può essere utilizzata per riutilizzare il codice.
- Tuttavia, è meglio usare la composizione invece dell'ereditarietà per riutilizzare il codice.
- Il modo in cui Movie riutilizza il codice di DiscountPolicy nel codice corrente è chiamato composizione.
- Se prendiamo Movie come classe superiore e la dividiamo in AmountDiscountMovie e PercentDiscountMovie, stiamo usando l'ereditarietà.
Ereditarietà
- Svantaggi dell'ereditarietà
- Viola l'incapsulamento.
- È necessario conoscere bene la struttura interna della classe padre.
- È probabile che la classe figlio debba essere modificata anche quando si modifica la classe padre.
- Rende la progettazione meno flessibile.
- La relazione tra classe padre e classe figlio viene determinata in fase di compilazione.
- È impossibile modificare il tipo di oggetto in fase di esecuzione.
- Tuttavia, con la composizione, è possibile sostituire l'istanza in fase di esecuzione tramite un metodo come changeDiscountPolicy() lato oggetto che utilizza l'oggetto.
- Viola l'incapsulamento.
Composizione
- Il metodo per riutilizzare il codice 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 combinare ereditarietà e composizione.
- Ad esempio, l'interfaccia DiscountPolicy deve necessariamente utilizzare l'ereditarietà per implementare sottoclassi.
Fonte
- Oggetti