Un oggetto di comunicazione full duplex è in conflitto con una singola responsabilità?

3

Sto scrivendo un'implementazione di Websocket in Java e l'ho configurato in modo tale che sostanzialmente avvolge un InputStream e un OutputStream e ha metodi pubblici sia per l'invio che per la ricezione. Mentre input e output sono correlati, sono anche completi di opposti e condividono pochissime funzionalità. Avrebbe più senso avere invece le classi WebsocketInput e WebsocketOutput?

La classe Socket di Java non ha davvero metodi per l'invio e la ricezione, oltre a fornire un InputStream e OutputStream. Non sono a conoscenza di classi comunemente usate in Java che incapsulino sia la lettura che la scrittura, ma è sbagliato suddividerle qui, poiché nessun utente avrebbe molto di più per la metà di un Websocket. Quale sarebbe l'approccio migliore qui?

    
posta codebreaker 01.08.2016 - 23:58
fonte

4 risposte

3

Oltre alle altre ottime risposte qui, un modo per pensarci è che non si sta migliorando realmente il livello di astrazione (nella direzione di una capacità full duplex) applicando singoli wrapper all'ingresso & flussi di output.

Anche se è vero che l'input & i flussi di output forniscono individualmente la propria responsabilità quando vengono visualizzati al loro livello di astrazione: d'altra parte, il pacchetto di input e amp; l'output messo insieme forma un livello più alto di astrazione, il flusso full duplex. Avere un livello più alto di astrazione, quando lo osserviamo in questo modo: ha una sua singola responsabilità, l'accoppiamento di un input appropriato e amp; flusso di output per formare un collegamento com full duplex.

Un suggerimento che suggerisce di innalzare il livello di astrazione combinando i due insieme perché ora hai una singola entità che fornirà full duplex, e puoi passare ad altri, e specialmente considerando che per confronto:

Se avvolgi input e amp; output individualmente e separatamente, si dovrebbe (ancora) avere due astrazioni da passare in giro, e i clienti dovrebbero preoccuparsi di (potenzialmente i dettagli di) accoppiare i due, se non almeno tenerli insieme quando passano intorno, per formare il pieno astrazione duplex. (Potresti ancora mettere un input avvolto e un'uscita insieme per manifestare finalmente una buona astrazione full duplex, ma qual è il punto dei wrapper intermedi?)

Quindi, mentre i flussi unidirezionali sottostanti hanno ciascuno una propria responsabilità, così una classe che li raggruppa insieme ha una sua singola responsabilità. Questi non si escludono a vicenda: perché quest'ultimo è ad un livello più alto di astrazione. Nel loro insieme, queste classi presentano una stratificazione, che è un modo per mantenere i progetti focalizzati sulla loro singola responsabilità. La stratificazione è il punto in cui un'astrazione viene implementata interamente dalle astrazioni nello strato successivo, senza dover andare più in basso. (La stratificazione è una tecnica che mi piace ridurre la complessità di progetti software molto grandi.)

    
risposta data 02.08.2016 - 02:07
fonte
4

Se vuoi dividerlo in più classi, l'approccio Java è esattamente come ti avvicineresti.

  • classe Socket
    • metodo getInputStream restituisce InputStream
    • metodo getOutputStream restituisce OutputStream
    • altri metodi che si applicano al Socket stesso e che non possono essere controllati singolarmente dall'aspetto di input o dall'aspetto di output.

In breve:

  • Il meccanismo sottostante è un socket (tecnicamente parlando).
    • È impossibile per te provare a nascondere questo meccanismo full-duplex dai tuoi utenti, perché non funzionerà in questo modo (come sottolineato da altri risponditori).
    • In altre parole, è meglio non suddividere questa classe di meccanismo in due classi indipendenti.
  • Tuttavia, è consentito fornire una facciata o interfacce che espongono ciascuna un singolo aspetto (input o output).
    • Questo soddisfa il principio di segregazione dell'interfaccia.

Questo è esattamente ciò che fa Java.

L'elenco delle alternative è:

  • Una classe principale, più due classi di facciata a cui è possibile accedere dalla classe principale (discussa sopra)
  • Una classe, due o più interfacce. Per chiamare i metodi su ciascuna interfaccia, l'utente esegue un cast di interfaccia.
  • Solo una classe principale. Tutti i metodi corrispondenti ad entrambi gli aspetti (flusso di input e flusso di output) sono accumulati nella classe principale.

Le ultime due opzioni non consentono conflitti di nome del metodo. In altre parole, oltre a essere più difficile per gli utenti, è anche più difficile dare nomi ai metodi.

La terza opzione è la meno flessibile. Il codice scritto per utilizzare quella classe principale non può essere adattato, ad esempio, a una comunicazione full duplex formata dall'accoppiamento di due comunicazioni half-duplex.

D'altra parte, potresti già avere un intero design per il protocollo di comunicazione. In questo caso, non è necessario esporre alcun dettaglio di livello inferiore (a parte ciò che è necessario per gestire le connessioni). Invece hai solo bisogno di esporre le funzionalità del tuo protocollo di comunicazione. In altre parole, non è necessario scrivere una classe generica se non è necessaria.

Ad esempio, invece di operare a livello di flusso di byte, potresti voler avere una classe che manda o riceve messaggi strutturati e convalidati. Se tale classe esiste nel tuo progetto, tale classe può essere scritta per usare direttamente la classe Socket, saltando così un livello di astrazione.

    
risposta data 02.08.2016 - 01:09
fonte
2

Una linea di comunicazione full duplex è una singola responsabilità . Tratta di conseguenza.

    
risposta data 02.08.2016 - 00:20
fonte
1

È necessario avere un motivo per racchiudere i flussi di input e di output piuttosto che utilizzarli direttamente. Potresti avere un cliente che ne ha bisogno entrambi in coppia. Forse i dettagli di quella coppia cambiano insieme.

Se questa ragione è una ragione e non due ragioni, allora ci sarà sempre una sola ragione per cui la classe cambierà. Se puoi dire che stai bene.

Questo problema non riguarda quante forme di comunicazione sono trattate nella classe. Riguarda quanti motivi sceglieresti in questa classe.

Questa classe potrebbe essere il wrapper che registra tutto ciò che è stato inviato attraverso di esso. Potrebbe essere quello che invia tutto a dev / null. Potrebbe essere quello che invia tutto su dove dovrebbe andare. Soddisfare questi 3 motivi dovrebbe produrre 3 classi. Non 6. Non 9.

Quindi sì la comunicazione full duplex è una singola responsabilità. Stai seguendo il principio della responsabilità unica se questo è ciò che fornisce la classe. Non di più. Non meno.

    
risposta data 02.08.2016 - 00:16
fonte

Leggi altre domande sui tag