Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Java OOP: Disaccoppiamento nello scambio dei messaggi

É possibile migliorare il disaccoppiamento tra classi anche facendo attenzione allo scambio di messaggi: in questo articolo forniamo alcune idee per applicare correttamente il principio OCP (Open Closed Principle), così da rendere maggiormente aperte alle estensioni e chiuse alle modifiche le nostre classi.
É possibile migliorare il disaccoppiamento tra classi anche facendo attenzione allo scambio di messaggi: in questo articolo forniamo alcune idee per applicare correttamente il principio OCP (Open Closed Principle), così da rendere maggiormente aperte alle estensioni e chiuse alle modifiche le nostre classi.
Link copiato negli appunti

Nei precedenti articoli sulle strategie utili a migliorare il disaccoppiamento (Disaccoppiamento Lost Identity, Disaccoppiamento totale con Protezione Implicita) abbiamo visto come esistano diversi fattori che determinano l’accoppiamento tra unità software: in particolare abbiamo evidenziato come le classi in java e addirittura le firme dei metodi, siano fattori che possono promuovere una politica di sviluppo software poco propensa al disaccoppiamento tra le classi.

Questi fattori vanno contro il principio OCP (Open Closed Principle) secondo il quale una classe o più in generale un software, dovrebbe essere aperto alle estensioni e chiuso alle modifiche.

Possiamo quindi tranquillamente affermare che lo scambio di messaggi sia anch'esso un fattore che accentua l'accoppiamento tra classi. Spesso poi in implementazioni di uso comune quando una classe A chiama un metodo su una Classe B quest'ultima ha necessità di capire la tipologia del messaggio ricevuto e dieffettuare un casting in locale.
Questo può dunque essere visto come elemento accoppiante, anche se in realtà non fa parte di questo contesto.

scambio messaggi

Partiamo da un presupposto di base e che cioè non necessariamente una classe Source per richiamare un metodo sulla classe Target al quale passare un parametro debba necessariamente farlo attraverso quel metodo. Cioè più semplicemente, deve esistere un modo per far si che una classe Source richiami un metodo printMessage(String message) su una classe target senza inviargli message.

La nostra tesi è che se questo fosse possibile si otterrebbe un ulteriore grado di disaccoppiamento.

Per il casting in locale questo è un tema che riprenderemo a fine articolo e che in qualche modo verrà risolto specializzando i metodi, come vedremo in seguito.

Creiamo un progetto java e chiamiamolo DecouplingCommunication creiamo quindi la seguente classe nel relativo package:

package com.sperimental;
import java.util.Hashtable;
public class DataShared {
	private Hashtable queue = new Hashtable();
	public String getStringProperty(String source, String key) {
		return (String) queue.get(key);
	}
	public void setProperty(String source , String key, Object prop) {
		queue.put(key, prop);
	}
}

DataShared è una classe che utilizzeremo per il transito del messaggio tra due classi: Source e Target. Creiamo la seguente interfaccia:

package com.sperimental;
public interface PrinterInterface {
	public void printMessage();
}

E le due classi Source e Target:

package com.sperimental;
public class Source {
	private DataShared ds;
	private PrinterInterface pi;
	private Source() {
		super();
	}
	public Source(DataShared ds,PrinterInterface pi) {
		super();
		this.ds = ds;
		this.pi = pi;
	}
	public void foo() {
		ds.setProperty(this.getClass().getName(), "key Message4Target","messaggio da Source per Target!");
		pi.printMessage();
	}
}
package com.sperimental;
public class Target implements PrinterInterface {
	private DataShared ds;
	private Target() {
		super();
	}
	public Target(DataShared ds) {
		super();
		this.ds = ds;
	}
	public void printMessage() {
		String msg= ds.getStringProperty(this.getClass().getName(), "key Message4Target");
		System.out.println("messaggio ricevuto:" + msg);
	}
}

Cerchiamo ora di fare un po' di chiarezza analizzando il codice:

public void foo() {
	ds.setProperty(
		this.getClass().getName(),
		"key Message4Target",
		"messaggio da Source per Target!"
	);
	pi.printMessage();
}

Utilizza una istanza condivisa di DataShared per definire il valore della property da inviare alla classe Target. In caso di memorizzazione il tipo di dato che viene memorizzato da DataShared non è specificato: il metodo corrispondente in DataShared accetta come parametro da memorizzare un valore di tipo Object:

public class DataShared {
	private Hashtable queue = new Hashtable();
	public void setProperty(String source , String key, Object prop) {
		queue.put(key, prop);
	}
}

La classe Target nel metodo printMessage():

public void printMessage() {
	String msg= ds.getStringProperty(
		this.getClass().getName(),
		"key Message4Target"
	);
	System.out.println("messaggio ricevuto:" + msg);
}

recupera la property e la stampa.

Facciam oa questo punto alcune considerazioni:

  • Le classi Source e Target non hanno accoppiamento legato ai messaggi; "normalmente" quando
    Source richiama il metodo printMessage() di Target dovrebbe passargli il messaggio che viene invece memorizzato nel DataShared per il transito.
  • Quando viene recuperato il messaggio da Target nel metodo printMessage() non è necessario un casting esplicito perchè il metodo getStringproperty()’ è specializzato.
  • DataShared potrebbe anche tenere traccia dei messaggi e del loro flusso.
  • Source e Target sono tra loro disaccoppiate tramite interfaccia e devono entrame condividere la stessa istanza di DataShared.
  • Possono essere considerate tranquillamente precauzioni per la Thread-Safety.

Questo articolo approfondisce una tematica che riguarda i limiti della metodologia OOP: aldilà dell'aspetto pratico ci sarà utile come introduzione al prossimo articolo di questa serie di approfondimenti su Java e OOP, dedicato alla Programmazione Data Centric.


Ti consigliamo anche