Sostituzione delle dipendenze dirette con la messaggistica

A volte un modulo ha solo bisogno di notificare agli altri che si sono verificati alcuni eventi/modifiche in esso, e non importa cosa succede a queste informazioni in seguito.

In questo caso, i moduli non devono assolutamente "conoscersi l'un l'altro", cioè contenere collegamenti diretti e interagire direttamente, ma è sufficiente solo scambiarsi messaggi (messaggi) o eventi (eventi).

A volte sembra che la comunicazione del modulo tramite messaggistica sia molto più debole della dipendenza diretta. Infatti, poiché i metodi non vengono chiamati, non ci sono informazioni sulle classi. Ma questa non è altro che un'illusione.

Invece dei nomi dei metodi, la logica inizia ad essere legata ai tipi di messaggio, ai loro parametri e ai dati trasmessi. La connettività di tali moduli è macchiata.

Era come: chiamiamo metodi - c'è connettività, non chiamiamo metodi - non c'è connettività. Ora immagina che il modulo A inizi a inviare dati leggermente diversi nei suoi messaggi. Allo stesso tempo, tutti i moduli dipendenti da questi messaggi non funzioneranno correttamente.

Supponiamo che, in precedenza, durante l'aggiunta di un nuovo utente, il modulo di autorizzazione inviasse il messaggio USER_ADDED e, dopo l'aggiornamento, iniziasse a inviare questo messaggio durante il tentativo di registrazione e indicasse inoltre la registrazione riuscita o meno nei parametri.

Pertanto, è molto importante implementare il meccanismo dei messaggi in modo molto competente. Ci sono vari modelli per questo.

Osservatore. Viene utilizzato nel caso di dipendenza uno-a-molti, quando molti moduli dipendono dallo stato di uno, quello principale. Utilizza il meccanismo di mailing, il che significa che il modulo principale invia semplicemente gli stessi messaggi a tutti i suoi abbonati, ei moduli interessati a queste informazioni implementano l'interfaccia "abbonato" e si iscrivono alla mailing list.

Questo approccio è ampiamente utilizzato nei sistemi con un'interfaccia utente, consentendo al nucleo dell'applicazione (modello) di rimanere indipendente mentre informa le interfacce associate che qualcosa è cambiato e deve essere aggiornato.

Qui il formato del messaggio è standardizzato a livello di sistema operativo, i cui sviluppatori devono occuparsi della retrocompatibilità e di una buona documentazione.

L'organizzazione dell'interazione attraverso la distribuzione di messaggi ha un ulteriore "bonus": l'esistenza facoltativa di "abbonati" ai messaggi "pubblicati" (ovvero inviati). Un sistema ben progettato come questo consente di aggiungere/rimuovere moduli in qualsiasi momento.

Autobus di messaggistica

Puoi organizzare lo scambio di messaggi e utilizzare il modello Mediatore per questo in un modo diverso .

Viene utilizzato quando esiste una dipendenza molti-a-molti tra i moduli. Il mediatore funge da intermediario nella comunicazione tra i moduli, fungendo da centro di comunicazione ed eliminando la necessità che i moduli facciano esplicito riferimento l'uno all'altro.

Di conseguenza, l'interazione dei moduli tra loro ("tutto con tutti") è sostituita dall'interazione dei moduli solo con un intermediario ("uno con tutti"). Si dice che il mediatore incapsula l'interazione tra più moduli.

Autobus di messaggistica

Questo è il cosiddetto intermediario intelligente . È lì che gli sviluppatori molto spesso iniziano ad aggiungere le loro stampelle, che influenzano il comportamento dei singoli moduli attivando / disattivando la ricezione di determinati messaggi.

Un tipico esempio di vita reale è il controllo del traffico aeroportuale. Tutti i messaggi dagli aerei vanno alla torre di controllo del controllore invece di essere inviati direttamente tra gli aerei. E il controllore prende già decisioni su quali aerei possono decollare o atterrare e, a sua volta, invia messaggi agli aerei.

Importante! I moduli possono scambiarsi non solo semplici messaggi, ma anche oggetti di comando. Tale interazione è descritta dal modello Command . La linea di fondo è incapsulare una richiesta per eseguire un'azione specifica come oggetto separato.

Infatti, questo oggetto contiene un unico metodo execute() , che poi permette di passare questa azione ad altri moduli per l'esecuzione come parametro e in genere di eseguire con l'oggetto comando eventuali operazioni eseguibili su oggetti ordinari.

Legge di Demetra

La Legge di Demetra proibisce l'uso di dipendenze implicite: "L'oggetto A non deve poter accedere direttamente all'oggetto C se l'oggetto A ha accesso all'oggetto B e l'oggetto B ha accesso all'oggetto C".

Ciò significa che tutte le dipendenze nel codice devono essere "esplicite": classi / moduli possono utilizzare solo le "loro dipendenze" nel loro lavoro e non devono passare attraverso di esse ad altri. Un buon esempio è un'architettura a tre livelli. Il livello dell'interfaccia dovrebbe funzionare con il livello logico, ma non dovrebbe interagire direttamente con il livello del database.

In breve, anche questo principio è formulato in questo modo: "Interagisci solo con amici intimi e non con amici di amici". In questo modo si ottiene una minore coerenza del codice, nonché una maggiore visibilità e trasparenza del suo design.

La Legge di Demetra attua il già citato “principio della conoscenza minima”, che è alla base dell'accoppiamento libero e consiste nel fatto che un oggetto/modulo dovrebbe conoscere il minor numero possibile di dettagli sulla struttura e proprietà di altri oggetti/moduli e qualsiasi cosa in generale, inclusi i suoi componenti .

Un'analogia dalla vita: se vuoi che il cane corra, è stupido comandare le sue zampe, è meglio dare il comando al cane, e lei stessa si occuperà delle sue zampe.

Composizione invece di eredità

Questo è un argomento molto ampio e interessante e merita almeno una lezione a parte. Molte copie sono state rotte su questo argomento su Internet fino a quando non è stato raggiunto un consenso - usiamo l'ereditarietà al minimo, la composizione - al massimo.

Il punto è che l'ereditarietà fornisce effettivamente la connessione più forte tra le classi, quindi dovrebbe essere evitata. Questo argomento è ben trattato nell'articolo di Herb Sutter " Preferisci la composizione all'ereditarietà ".

Quando inizi a imparare i design pattern, ti imbatterai in tutta una serie di pattern che governano la creazione di un oggetto o la sua struttura interna. A proposito, posso consigliare in questo contesto di prestare attenzione al pattern Delegate / Delegate e al pattern Component , che provengono dai giochi .

Parleremo di più sui modelli un po 'più tardi.

undefined
3
Опрос
Software architecture, client-server architecture, MVC,  14 уровень,  9 лекция
недоступен
Software architecture, client-server architecture, MVC
Software architecture, client-server architecture, MVC