Introduzione
Robert L. Glass sosteneva che la pratica precedesse la teoria. Lo sviluppo del software, in particolare, è un campo in cui la pratica è in anticipo rispetto alla teoria, e gli sviluppatori traggono il massimo vantaggio quando si sporcano le mani con codice concreto. Pertanto, metteremo da parte per un momento teoria e concetti e daremo un'occhiata a un semplice programma.
Implementare un'applicazione per la vendita di biglietti
- Stiamo pianificando un piccolo evento per promuovere un piccolo teatro.
- Contenuto dell'evento: inviare inviti gratuiti per assistere allo spettacolo a spettatori selezionati tramite estrazione a sorte.
- Dobbiamo separare gli spettatori che hanno vinto l'estrazione da quelli che non hanno vinto.
- Spettatori vincenti: scambiare l'invito con un biglietto.
- Spettatori perdenti: acquistare il biglietto con denaro.
Codice di pratica: https://github.com/Java-Crew/objects-study/tree/jayon/src/main/java/chapter01/step01
Qual è il problema?
Robert Martin spiega le tre funzioni che un modulo software (indipendentemente dalle dimensioni, come una classe, un pacchetto o una libreria, qualsiasi elemento che costituisca un programma) dovrebbe avere.
- Funziona correttamente durante l'esecuzione.
- Esiste per essere modificato.
- Le modifiche devono essere possibili con un minimo sforzo.
- Comunica con chi legge il codice.
- Deve essere facile da leggere e comprendere per gli sviluppatori.
L'applicazione per la vendita di biglietti precedente soddisfa il primo vincolo, ovvero funzionare correttamente, ma non soddisfa gli obiettivi di facilità di modifica e comunicazione.
Codice inaspettato
Diamo un'occhiata al motivo per cui non soddisfa l'obiettivo della comunicazione.
- Cosa fa il metodo enter() della classe Theater
- Il teatro apre la borsa dello spettatore e controlla se contiene un invito.
- Se la borsa contiene un invito, ordina al venditore di biglietti di trasferire il biglietto conservato nella biglietteria nella borsa dello spettatore.
- Se la borsa non contiene un invito, estrae dalla borsa dello spettatore la quantità di denaro corrispondente al prezzo del biglietto, acquista il biglietto e lo inserisce nella borsa.
- Dal punto di vista dello spettatore, deve assistere a un terzo, il teatro, che rovista nella sua borsa, prende i suoi soldi e mette un biglietto nella borsa.
- Dal punto di vista del venditore di biglietti, deve assistere a un terzo, il teatro, che manipola senza permesso biglietti e denaro nella biglietteria.
- Il codice comprensibile è un codice il cui comportamento non si discosta eccessivamente dalle nostre aspettative, e questo teatro non è in linea con le nostre aspettative.
- Lo spettatore dovrebbe prendere i soldi dalla sua borsa e pagarli al venditore di biglietti per ricevere il biglietto.
- Il venditore di biglietti dovrebbe prendere il biglietto direttamente dalla biglietteria e consegnarlo allo spettatore, ricevendo i soldi da quest'ultimo e conservandoli nella biglietteria.
- Inoltre, per comprendere il metodo enter(), è necessario ricordare tutti i dettagli.
- Audience ha un oggetto Bag.
- La borsa contiene denaro e biglietti.
- TicketSellet vende biglietti presso TicketOffice, e TicketOffice conserva denaro e biglietti.
Codice vulnerabile alle modifiche
Il metodo enter() presuppone due condizioni.
- Lo spettatore porta sempre con sé una borsa per conservare denaro e inviti.
- Il venditore di biglietti vende biglietti solo alla biglietteria.
E se la situazione fosse diversa?
- Lo spettatore potrebbe non avere una borsa.
- Lo spettatore potrebbe utilizzare una carta di credito invece di contanti.
- Il venditore di biglietti potrebbe vendere biglietti anche al di fuori della biglietteria.
Ad esempio, per soddisfare la prima richiesta, dovremmo rimuovere l'oggetto Bag di Audience e modificare il metodo enter() della classe Theater. Questo perché la classe Theater si basa su informazioni troppo dettagliate, come il fatto che lo spettatore abbia una borsa e che il venditore di biglietti venda i biglietti solo alla biglietteria. Se anche solo uno di questi dettagli cambia, dovremmo modificare sia la classe interessata che le classi a essa collegate (ad esempio, Theater).
Questo è un problema legato alla dipendenza tra gli oggetti, e la dipendenza implica un impatto sulle modifiche. Tuttavia, poiché l'obiettivo della progettazione orientata agli oggetti è costruire una comunità di oggetti che collaborano e dipendono l'uno dall'altro, non dobbiamo eliminare a priori le dipendenze, ma dobbiamo mantenere solo le dipendenze minime necessarieed eliminare quelle non necessarie.
Quando la dipendenza tra gli oggetti è eccessiva, si dice che l'accoppiamentoè alto, e maggiore è l'accoppiamento tra due oggetti, maggiore è la probabilità che vengano modificati insieme. Pertanto, l'obiettivo della progettazione è ridurre l'accoppiamento tra gli oggetti per rendere le modifiche più facili.
Migliorare la progettazione
Theater non ha bisogno di sapere se lo spettatore ha una borsa o se il venditore di biglietti vende biglietti alla biglietteria. Theater vuole solo che lo spettatore entri nel teatro. Pertanto, dobbiamo rendere lo spettatore e il venditore di biglietti entità autonome, in modo che gestiscano autonomamente il denaro e l'invito nella borsa e i biglietti e le tariffe di vendita nella biglietteria.
Aumentare l'autonomia
Un oggetto che esegue solo attività strettamente correlate e delega attività non correlate ad altri oggetti si dice che abbia un'elevata coesione. Creare oggetti autonomi che gestiscono i propri dati riduce l'accoppiamento e aumenta la coesione.
Programmazione procedurale e programmazione orientata agli oggetti
- Procedurale
- Il metodo enter() di Theater è un processo, mentre Audience, TicketSeller, Bag e TicketOffice sono dati.
- Il posizionamento di processi e dati in moduli separati è chiamato programmazione procedurale.
- Ci sono molti codici che violano la nostra intuizione. (ad esempio, lo spettatore gestisce autonomamente denaro e inviti).
- È difficile limitare l'impatto delle modifiche ai dati.
- La responsabilità è gestita in modo centralizzato. (Theater gestisce tutto)
- Orientato agli oggetti
- Il posizionamento di dati e processi all'interno dello stesso modulo è chiamato programmazione orientata agli oggetti.
- Possiamo scrivere codice che corrisponde alla nostra intuizione.
- L'impatto delle modifiche ai dati può essere efficacemente limitato tramite l'incapsulamento.
- Ogni oggetto è responsabile di se stesso.
Codice di pratica: https://github.com/Java-Crew/objects-study/tree/jayon/src/main/java/chapter01/step02
Si può migliorare ulteriormente.
- La classe Bag della classe Audience è ancora un'entità passiva trascinata dalla classe Audience, quindi dobbiamo rendere la classe Bag un'entità autonoma.
- Anche TicketOffice della classe TicketSeller è gestito a piacimento da TicketSeller. Dobbiamo rendere TicketOffice un'entità autonoma.
- Tuttavia, dopo la modifica, TicketOffice ha un ulteriore accoppiamento con Audience.
- Come questo, la progettazione richiede un'attenta valutazione dei compromessi. In questo caso, potremmo concordare di rendere TicketOffice un oggetto relativamente passivo per ridurre l'accoppiamento con Audience.
Codice di pratica: https://github.com/Java-Crew/objects-study/tree/jayon/src/main/java/chapter01/step03
Sì, è una bugia!
- Nella realtà, anche se qualcosa è passivo, nel mondo della programmazione orientata agli oggetti, tutto diventa attivo e autonomo.
- È utile utilizzare la personificazione e pensare agli oggetti passivi come se stessero ridendo, chiacchierando e arrabbiandosi.
Progettazione orientata agli oggetti
Perché è necessaria la progettazione?
- La progettazione è il posizionamento del codice.
- Una buona progettazione è quella che soddisfa pienamente le esigenze attuali e allo stesso tempo consente di affrontare i cambiamenti futuri in modo fluido.
Progettazione orientata agli oggetti
- Il codice modificabile è un codice facile da capire.
- Il paradigma orientato agli oggetti ci aiuta a scrivere codice nel modo in cui vediamo il mondo.
- Gli oggetti sono entità autonome che sono responsabili dei propri dati.
- Una buona progettazione orientata agli oggetti è una progettazione che gestisce correttamente le dipendenze tra gli oggetti che collaborano.
Fonti
- Oggetti
Commenti0