Che cos'è "accoppiamento libero?" Si prega di fornire esempi


172

Non riesco a sgridare il concetto di "accoppiamento lento". Suppongo che non aiuta il fatto che la parola "loose" di solito abbia una connotazione negativa, quindi dimentico sempre che l'accoppiamento loose è una buona cosa.

Qualcuno può mostrare un po 'di codice "prima" e "dopo" (o pseudocodice) che illustra questo concetto?


Non sono sicuro di come possa essere divorziato da una determinata lingua perché parte del concetto è come si usa una lingua per evitare che le unità di codice diventino troppo intrecciate l'una con l'altra. Noto anche che molte delle risposte ricorrono al codice per illustrare il concetto.
Onorio Catenacci,

11
Non sono completamente d'accordo, le funzionalità possono essere illustrate in modo diverso in diverse lingue ed è particolarmente evidente nelle lingue dinamiche e compilate. Ma il concetto è lo stesso in entrambi i modi.
Owen,

Sciolto contro stretto e accoppiamento contro disaccoppiamento . Taggare insieme non è sempre una buona cosa, a volte buono / a volte non buono ... Come dovremmo avere indipendenza nostra, così fanno le lezioni.
bonCodigo,

Risposte:


180

Prendi in considerazione una semplice applicazione del carrello che utilizza una classe CartContents per tenere traccia degli articoli nel carrello e una classe Ordine per l'elaborazione di un acquisto. L'Ordine deve determinare il valore totale dei contenuti nel carrello, potrebbe farlo in questo modo:

Esempio strettamente accoppiato:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

Notare come il metodo OrderTotal (e quindi la classe Order) dipende dai dettagli di implementazione delle classi CartContents e CartEntry. Se dovessimo provare a cambiare questa logica per consentire sconti, probabilmente dovremmo cambiare tutte e 3 le classi. Inoltre, se passiamo all'utilizzo di una raccolta Elenco per tenere traccia degli articoli, dovremmo modificare anche la classe Ordine.

Ora ecco un modo leggermente migliore per fare la stessa cosa:

Esempio meno accoppiato:

public class CartEntry
{
    public float Price;
    public int Quantity;

    public float GetLineItemTotal()
    {
        return Price * Quantity;
    }
}

public class CartContents
{
    public CartEntry[] items;

    public float GetCartItemsTotal()
    {
        float cartTotal = 0;
        foreach (CartEntry item in items)
        {
            cartTotal += item.GetLineItemTotal();
        }
        return cartTotal;
    }
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        return cart.GetCartItemsTotal() * (1.0f + salesTax);
    }
}

La logica specifica dell'implementazione dell'elemento pubblicitario del carrello o della raccolta del carrello o dell'ordine è limitata solo a quella classe. Quindi potremmo cambiare l'implementazione di una di queste classi senza cambiare le altre classi. Potremmo portare questo disaccoppiamento ancora migliorando il design, introducendo interfacce, ecc., Ma penso che tu capisca il punto.


Potresti espandere la risposta introducendo un ulteriore disaccoppiamento attraverso l'iniezione di dipendenza (sebbene il costruttore dovrebbe essere l'ideale)?
BAD_SEED,

4
@Wedge, non vedo alcun motivo per Orderavere una conoscenza di a Cart. Lo shopping dal vivo e la fatturazione sono due contesti diversi. Quando il cliente è pronto a pagare, potresti avere un processo responsabile per tradurre CartEntries in qualcosa di significativo per il Order. In questo modo la Orderclasse verrebbe anche istanziata e utilizzata senza a Cart.
Plalx,

@Wedge Potresti reagire al mio commento per favore?
plalx,

Bene e semplicemente spiegato. Ho iniziato a vedere la luce su "... Nota come il metodo OrderTotal (e quindi la classe Order) dipende dai dettagli di implementazione delle classi CartContents e CartEntry .."
okey_on

Questo esempio è presentato chiaramente. Tuttavia in questi giorni, sempre più architetti concordano sul fatto che questo stile eccessivamente orientato agli oggetti è una cattiva pratica. Non ha senso nascondere i dettagli di "implementazione" di CartEntrye CartContents. Dal momento che questi hanno un significato perfettamente chiaro, dovrebbero essere semplicemente modellati come dati morti. in termini di database, tutto ciò che serve qui è una tabellaCREATE TABLE entry (price INTEGER, quantity INTEGER)
Jo So

160

Molti prodotti integrati (soprattutto di Apple) come iPod , iPad sono un buon esempio di accoppiamento stretto: una volta che la batteria è scarica potresti anche acquistare un nuovo dispositivo perché la batteria è saldata e non si allenterà, rendendo così la sostituzione molto costoso. Un lettore con accoppiamento lento consentirebbe di cambiare la batteria senza sforzo.

Lo stesso vale per lo sviluppo del software: è generalmente (molto) meglio avere un codice liberamente accoppiato per facilitare l'estensione e la sostituzione (e per facilitare la comprensione delle singole parti). Ma, molto raramente, in circostanze speciali un accoppiamento stretto può essere vantaggioso perché la stretta integrazione di diversi moduli consente una migliore ottimizzazione.


L'accoppiamento lento o stretto è buono? Come decidere di implementare un accoppiamento lento o stretto?
Sreekanth Karumanaghat,

2
grazie per questo grande esempio. ho trascorso molto tempo su altre risposte ma non valeva la pena
alamin

1
Sreekanth Karumanaghat, preferiresti spendere meno soldi solo per una batteria e avere di nuovo un iPod funzionante o preferiresti spendere molti soldi per un intero iPod?
Koshera,

1
@SreekanthKarumanaghat L'accoppiamento tipicamente lento è migliore perché promuove la modularità e quindi facilita la manutenzione del codice. Se si accoppiano strettamente le classi / librerie / codice, qualsiasi piccola modifica apportata in una classe dovrà essere implementata in tutte le classi che la utilizzano.
Kenny Worden,

56

Userò Java come esempio. Diciamo che abbiamo una classe che assomiglia a questa:

public class ABC
{
   public void doDiskAccess() {...}
}

Quando chiamo la lezione, dovrò fare qualcosa del genere:

ABC abc = new ABC();

abc. doDiskAccess();

Fin qui tutto bene. Ora diciamo che ho un'altra classe che assomiglia a questa:

public class XYZ
{
   public void doNetworkAccess() {...}
}

Sembra esattamente lo stesso di ABC, ma diciamo che funziona sulla rete anziché sul disco. Quindi ora scriviamo un programma come questo:

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

Funziona, ma è un po 'ingombrante. Potrei semplificarlo con un'interfaccia come questa:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

Ora il mio codice può apparire così:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

Vedi quanto è più pulito e semplice da capire? Abbiamo appena compreso il primo principio di base dell'accoppiamento libero: l'astrazione. La chiave da qui è assicurarsi che ABC e XYZ non dipendano da alcun metodo o variabile delle classi che li chiamano. Ciò consente ad ABC e XYZ di essere API completamente indipendenti. O in altre parole, sono "disaccoppiati" o "liberamente accoppiati" dalle classi genitore.

E se avessimo bisogno di comunicazione tra i due? Bene, allora possiamo usare ulteriori astrazioni come un modello di evento per garantire che il codice genitore non debba mai accoppiarsi con le API che hai creato.


2
Questo esempio ha ancora un livello piuttosto elevato di accoppiamento. Proprio ora invece di essere accoppiati a una singola classe, ce ne sono due tra cui scegliere. In questo esempio si presume che saranno disponibili solo due implementazioni "eseguibili". Nel qual caso non è nemmeno richiesta un'interfaccia.
Owen,

Questi metodi denominati Run * e Do * sono per me un grande odore di codice. Potresti anche rifattorizzare questo aspetto usando IHandleStuff o IFrobnicateThings. Runnable è un termine molto, troppo generico in questo caso.
Wedge

8
Owen, piccola fa un passo amico mio. Se non capisce l'accoppiamento, come capirà cosa lo acquista un modello di fabbrica? Questo esempio di codice lo mette sulla strada giusta. L'intento è che capirà meglio il problema e realizzerà come astrarre la creazione degli oggetti.
64BitBob,

6
Sarebbe più leggibile se ABC e XYZ fossero ribattezzati con qualcosa del genere DiskAccessore NetworkAccessor? Non so java ...
MusiGenesis,

Utilizza anche il modello di progettazione di fabbrica? Perché stiamo creando nuovi oggetti XYZ o ABC a seconda delle necessità.
munmunbb,

37

Siamo spiacenti, ma "accoppiamento lento" non è un problema di codifica, è un problema di progettazione. Il termine "accoppiamento libero" è intimamente correlato allo stato desiderabile di "alta coesione", essendo opposto ma complementare.

L'accoppiamento allentato significa semplicemente che i singoli elementi di progettazione dovrebbero essere costruiti in modo da ridurre la quantità di informazioni non necessarie che devono conoscere su altri elementi di progettazione.

L'alta coesione è una specie di "accoppiamento stretto", ma l'alta coesione è uno stato in cui gli elementi di design che hanno davvero bisogno di conoscersi sono progettati in modo da lavorare insieme in modo pulito ed elegante.

Il punto è che alcuni elementi di design dovrebbero conoscere i dettagli di altri elementi di design, quindi dovrebbero essere progettati in questo modo e non accidentalmente. Altri elementi di design non dovrebbero conoscere dettagli su altri elementi di design, quindi dovrebbero essere progettati in questo modo, intenzionalmente, anziché in modo casuale.

L'implementazione di questo è lasciata come esercizio per il lettore :).


33

Il codice strettamente associato si basa su un'implementazione concreta. Se ho bisogno di un elenco di stringhe nel mio codice e lo dichiaro così (in Java)

ArrayList<String> myList = new ArrayList<String>();

quindi dipendo dall'implementazione di ArrayList.

Se voglio cambiarlo in codice liberamente accoppiato, faccio del mio riferimento un tipo di interfaccia (o altro astratto).

List<String> myList = new ArrayList<String>();

Questo mi impedisce di chiamare qualsiasi metodo myListspecifico per l'implementazione di ArrayList. Sono limitato ai soli metodi definiti nell'interfaccia Elenco. Se in seguito decido che ho davvero bisogno di un LinkedList, ho solo bisogno di cambiare il mio codice in un posto, dove ho creato il nuovo Elenco, e non in 100 posti in cui ho effettuato chiamate ai metodi ArrayList.

Ovviamente, puoi creare un'istanza di una ArrayList usando la prima dichiarazione e trattenerti dal non usare alcun metodo che non faccia parte dell'interfaccia List, ma l'uso della seconda dichiarazione rende il compilatore onesto.


Questo non si riferisce a cosa sia effettivamente l'accoppiamento . Vedi stackoverflow.com/questions/39946/coupling-and-cohesion per alcune buone risposte.
Rogério,

@Rogerio: penso che riguardi. Forse sei confuso da altre definizioni di "accoppiamento", ma dovresti leggere Accoppiamento libero . "L'accoppiamento forte si verifica quando una classe dipendente contiene un puntatore direttamente a una classe concreta che fornisce il comportamento richiesto ... L'accoppiamento lento si verifica quando la classe dipendente contiene un puntatore solo a un'interfaccia, che può quindi essere implementata da una o più classi concrete ". Nel mio esempio, il mio codice verrebbe accoppiato liberamente a un ArrayList tramite l'interfaccia Elenco.
Bill the Lizard,

@Bill: Grazie per il link, ma l'articolo mi sembra completamente falso. Sembra "reinterpretare" le idee di un altro dominio (comportamento organizzativo), dando una definizione di "accoppiamento libero" che contraddice la definizione specifica del software originale di Larry Constantine: en.wikipedia.org/wiki/Coupling_(computer_science) .
Rogério,

@Rogerio: l'articolo di Costantino è stato scritto nel 1974. È probabile che negli ultimi 36 anni siano state fatte molte reinterpretazioni, ma non credo che l'articolo di Wikipedia sia la sua fonte. Ad esempio, schemi come Dependency Injection si basano su interfacce per allentare l'accoppiamento proprio come descrivo nella mia risposta.
Bill the Lizard,

2
@Bill: Certo, il lavoro di Constantine sul design strutturato è roba vecchia, ma non vedo alcun motivo per invalidarlo o reinterpretarlo radicalmente. I concetti originali di coesione e accoppiamento sono alla base del design orientato agli oggetti, tanto quanto l'ereditarietà e il polimorfismo. DI (un articolo migliore è martinfowler.com/articles/injection.html ) è semplicemente una tecnica per la configurazione esterna dei plug-in (interfacce astratte con implementazioni selezionate in fase di esecuzione tramite il codice di configurazione); un'altra di queste tecniche è il modello di Service Locator. DI e accoppiamento sono concetti indipendenti.
Rogério,

27

Il grado di differenza tra le risposte qui mostra perché sarebbe un concetto difficile da capire ma per dirlo nel modo più semplice che posso descriverlo:

Per farmi sapere che se ti lancio una palla, allora puoi prenderla, non ho davvero bisogno di sapere quanti anni hai. Non ho bisogno di sapere cosa hai mangiato a colazione e non mi interessa davvero chi è stata la tua prima cotta. Tutto quello che devo sapere è che puoi prenderlo. Se lo so, non mi importa se sono tu a lanciare una palla a te o tuo fratello.

Con linguaggi non dinamici come c # o Java ecc., Lo facciamo tramite le interfacce. Supponiamo quindi che abbiamo la seguente interfaccia:

public ICatcher
{
   public void Catch();
}

E ora diciamo che abbiamo le seguenti classi:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

Ora sia CatcherA che CatcherB implementano il metodo Catch, quindi il servizio che richiede un Catcher può usare uno di questi e non gliene frega davvero quale sia. Quindi un servizio strettamente accoppiato potrebbe istanziare direttamente un pescato

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

Quindi CatchService può fare esattamente ciò che si è prefissato di fare, ma utilizza CatcherA e utilizzerà sempre CatcherA. È codificato, quindi rimane lì fino a quando qualcuno arriva e lo refacturing.

Ora prendiamo un'altra opzione, chiamata iniezione di dipendenza:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

Quindi il calss che instansia CatchService può fare quanto segue:

CatchService catchService = new CatchService(new CatcherA());

o

CatchService catchService = new CatchService(new CatcherB());

Ciò significa che il servizio Catch non è strettamente accoppiato a CatcherA o CatcherB.

Esistono diverse altre strategie per servizi di accoppiamento non vincolato come questo, come l'uso di un framework IoC ecc.


1
Mi piace questo esempio meglio degli altri, poiché questo genere di cose accade nel mondo degli affari giorno per giorno. Se Class Person corre, Class Cat corre, Class Dog corre, ecc. Sarebbe un programma enorme per dettagliare tutte quelle classi che corre. Ma usare un'interfaccia chiamata run, in cui ogni classe fa la stessa cosa, rende il tuo programma molto più flessibile e gestibile. :)
sksallaj,

Spiegato davvero bene signore, giusto per chiarire nell'ultimo esempio che l'hai fatto con l'iniezione di dipendenza, e anche il primo esempio è liberamente accoppiato?
Ali Sajid,

Caspita, vecchia risposta commentata :). Quindi la risposta è no, il primo esempio ha una forte dipendenza da CatcherA, quindi sono fortemente accoppiati
Owen,

23

Puoi pensare all'accoppiamento (stretto o lento) come letteralmente alla quantità di sforzo che ci vorrebbe per separare una determinata classe dalla sua dipendenza da un'altra classe. Ad esempio, se ogni metodo nella tua classe avesse un piccolo blocco in fondo in cui hai fatto una chiamata a Log4Net per registrare qualcosa, allora diresti che la tua classe era strettamente accoppiata a Log4Net. Se invece la tua classe contenesse un metodo privato chiamato LogSomething che era l'unico posto che chiamava il componente Log4Net (e gli altri metodi invece tutti chiamati LogSomething), allora diresti che la tua classe è stata liberamente accoppiata a Log4Net (perché non richiederebbe molto sforzo per estrarre Log4Net e sostituirlo con qualcos'altro).


1
Quindi, "vagamente accoppiati" significa in realtà meno dipendenze? Ho ragione?
user314362

4
Non è realmente correlato al numero totale di dipendenze di una determinata classe. L'accoppiamento (stretto o lento) è in realtà una proprietà della relazione tra due classi. Quindi potresti avere una classe che è liberamente accoppiata ad altre 100 classi, o un'altra classe che è strettamente accoppiata ad altre 2 altre classi (per esempio).
MusiGenesis,

2
Cattivo esempio, direi: quello che hai è la duplicazione del codice, non l'accoppiamento stretto. E con un buon strumento di refactoring, tale duplicazione potrebbe essere eliminata in pochi secondi.
Rogério,

@Rogerio: probabilmente non è il miglior esempio. Mi piace 64BitBobla risposta migliore, me stesso.
MusiGenesis,

12

Definizione

In sostanza, l'accoppiamento è quanto un determinato oggetto o insieme di oggetti si basa su un altro oggetto o un altro insieme di oggetti per svolgere il suo compito.

Alto accoppiamento

Pensa a una macchina. Affinché il motore si avvii, è necessario inserire una chiave nell'accensione, girare, deve essere presente la benzina, deve verificarsi una scintilla, i pistoni devono sparare e il motore deve prendere vita. Si potrebbe dire che un motore di un'auto è fortemente accoppiato a molti altri oggetti. Questo è un accoppiamento elevato, ma non è proprio una brutta cosa.

Accoppiamento lasco

Pensa a un controllo utente per una pagina web che è responsabile per consentire agli utenti di pubblicare, modificare e visualizzare alcuni tipi di informazioni. Il controllo singolo potrebbe essere utilizzato per consentire a un utente di pubblicare una nuova informazione o modificare una nuova informazione. Il controllo dovrebbe essere in grado di essere condiviso tra due percorsi diversi: nuovo e modifica. Se il controllo è scritto in modo tale da richiedere un tipo di dati dalle pagine che lo contengono, allora si potrebbe dire che è troppo accoppiato. Il controllo non dovrebbe richiedere nulla dalla sua pagina contenitore.


7

È un concetto piuttosto generale, quindi gli esempi di codice non daranno l'intero quadro.

Un ragazzo qui al lavoro mi ha detto, "i modelli sono come frattali, puoi vederli quando ingrandisci molto da vicino e quando ingrandisci il livello dell'architettura".

Leggere la breve pagina di Wikipedia può darti un'idea di questa generalità:

http://en.wikipedia.org/wiki/Loose_coupling

Per quanto riguarda un esempio di codice specifico ...

Ecco un accoppiamento lento con cui ho lavorato di recente, dal materiale Microsoft.Practices.CompositeUI.

    [ServiceDependency]
    public ICustomizableGridService CustomizableGridService
    {
        protected get { return _customizableGridService; }
        set { _customizableGridService = value; }
    }

Questo codice dichiara che questa classe ha una dipendenza da un CustomizableGridService. Invece di riferirsi direttamente all'esatta implementazione del servizio, afferma semplicemente che richiede ALCUNA implementazione di quel servizio. Quindi in fase di esecuzione, il sistema risolve tale dipendenza.

Se ciò non è chiaro, puoi leggere una spiegazione più dettagliata qui:

http://en.wikipedia.org/wiki/Dependency_injection

Immagina che ABCCustomizableGridService sia l'imlpementazione che intendo collegare qui.

Se lo scelgo, posso estrarlo e sostituirlo con XYZCustomizableGridService o StubCustomizableGridService senza alcuna modifica alla classe con questa dipendenza.

Se avessi fatto direttamente riferimento a ABCCustomizableGridService, allora avrei bisogno di apportare modifiche a quello / quei riferimenti / i al fine di scambiare in un'altra implementazione del servizio.


6

L'accoppiamento ha a che fare con le dipendenze tra i sistemi, che potrebbero essere moduli di codice (funzioni, file o classi), strumenti in una pipeline, processi server-client e così via. Meno generali sono le dipendenze, più "strettamente accoppiate" diventano, dal momento che cambiare un sistema richiede cambiare gli altri sistemi che si basano su di esso. La situazione ideale è "accoppiamento libero" in cui un sistema può essere cambiato e i sistemi che dipendono da esso continueranno a funzionare senza modifiche.

Il modo generale per ottenere un accoppiamento libero è attraverso interfacce ben definite. Se l'interazione tra due sistemi è ben definita e rispettata da entrambi i lati, diventa più semplice modificare un sistema assicurando che le convenzioni non vengano infrante. Nella pratica si verifica comunemente che non viene stabilita un'interfaccia ben definita, con il risultato di un design sciatto e un accoppiamento stretto.

Qualche esempio:

  • L'applicazione dipende da una libreria. Sotto stretto accoppiamento, l'app si interrompe sulle versioni più recenti della lib. Google per "DLL Hell".

  • L'app client legge i dati da un server. Sotto stretto accoppiamento, le modifiche al server richiedono correzioni sul lato client.

  • Due classi interagiscono in una gerarchia orientata agli oggetti. In caso di accoppiamento stretto, le modifiche a una classe richiedono l'aggiornamento dell'altra classe affinché corrisponda.

  • Più strumenti da riga di comando comunicano in una pipe. Se sono strettamente accoppiati, le modifiche alla versione di uno strumento da riga di comando causeranno errori negli strumenti che leggono il suo output.


5

L'accoppiamento si riferisce a come classi strettamente diverse sono collegate tra loro. Le classi strettamente accoppiate contengono un elevato numero di interazioni e dipendenze.

Le classi liberamente accoppiate sono l'opposto in quanto le loro dipendenze reciproche sono ridotte al minimo e si affidano invece alle interfacce pubbliche ben definite l'una dell'altra.

Legos, i giocattoli che SNAP insieme sarebbero considerati vagamente accoppiati perché puoi semplicemente agganciare i pezzi e costruire qualsiasi sistema tu voglia. Tuttavia, un puzzle ha pezzi che sono strettamente accoppiati. Non puoi prendere un pezzo da un puzzle (sistema) e farlo scattare in un puzzle diverso, perché il sistema (puzzle) dipende molto dai pezzi molto specifici che sono stati creati specifici per quel particolare "disegno". I lego sono costruiti in un modo più generico in modo che possano essere utilizzati nella tua Lego House o nel mio Lego Alien Man.

Riferimento: https://megocode3.wordpress.com/2008/02/14/coupling-and-cohesion/


4

Due componenti sono fortemente accoppiati quando dipendono da una concreta attuazione reciproca.

Supponiamo di avere questo codice da qualche parte in un metodo nella mia classe:

this.some_object = new SomeObject();

Ora la mia classe dipende da SomeObject e sono altamente accoppiati. D'altra parte, diciamo che ho un metodo InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

Quindi il primo esempio può semplicemente usare SomeObject iniettato. Questo è utile durante i test. Con il normale funzionamento è possibile utilizzare classi pesanti, che utilizzano database, che utilizzano la rete, ecc., Mentre per i test che superano un'implementazione leggera e finta. Con un codice strettamente accoppiato non puoi farlo.

È possibile semplificare alcune parti di questo lavoro utilizzando i contenitori per l'iniezione delle dipendenze. Puoi leggere di più su DI su Wikipedia: http://en.wikipedia.org/wiki/Dependency_injection .

A volte è facile andare troppo lontano. Ad un certo punto devi rendere le cose concrete, o il tuo programma sarà meno leggibile e comprensibile. Quindi utilizzare queste tecniche principalmente al limite dei componenti e sapere cosa si sta facendo. Assicurati di sfruttare l'accoppiamento libero. In caso contrario, probabilmente non è necessario in quel luogo. DI potrebbe rendere il tuo programma più complesso. Assicurati di fare un buon compromesso. In altre parole, mantenere un buon equilibrio. Come sempre nella progettazione di sistemi. In bocca al lupo!


3

Prendi in considerazione un'app di Windows con FormA e FormB. FormA è il modulo principale e visualizza FormB. Immagina che FormB debba restituire i dati al suo genitore.

Se hai fatto questo:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB è strettamente accoppiato a FormA. FormB non può avere un genitore diverso da quello di tipo FormA.

Se invece FormB pubblica un evento e FormA si iscrive a quell'evento, FormB può inviare i dati attraverso quell'evento a qualunque abbonato abbia quell'evento. In questo caso quindi, FormB non sa nemmeno che sta parlando con il suo genitore; attraverso l'accoppiamento libero l'evento fornisce semplicemente parlare con gli abbonati. Qualsiasi tipo può ora essere genitore di FormA.

rp


3

Nell'informatica c'è un altro significato di "accoppiamento libero" che nessun altro ha pubblicato qui, quindi ... Ecco qui - si spera che tu mi dia un po 'di voti in modo che questo non sia perso in fondo all'heap! Sicuramente l'argomento della mia risposta appartiene a qualsiasi risposta esaustiva alla domanda ...

Il termine "Loose Coupling" è entrato per la prima volta nell'elaborazione come termine usato come aggettivo per l'architettura della CPU in una configurazione multi-CPU. Il suo termine di contropartita è "accoppiamento stretto". Loose Coupling è quando le CPU non condividono molte risorse in comune e lo stretto accoppiamento è quando lo fanno.

Il termine "sistema" può essere fonte di confusione qui, quindi ti preghiamo di analizzare attentamente la situazione.

Di solito, ma non sempre, più CPU in una configurazione hardware in cui esistono all'interno di un sistema (come nelle singole scatole "PC") sarebbero strettamente accoppiate. Con l'eccezione di alcuni sistemi ad altissime prestazioni che hanno sottosistemi che condividono effettivamente la memoria principale tra "sistemi", tutti i sistemi divisibili sono liberamente accoppiati.

I termini Tightly Coupled e Loosely Coupled sono stati introdotti prima dell'invenzione delle CPU multi-thread e multi-core, quindi questi termini potrebbero aver bisogno di alcuni compagni per articolare pienamente la situazione oggi. E, infatti, oggi si potrebbe benissimo avere un sistema che racchiude entrambi i tipi in un sistema complessivo. Per quanto riguarda gli attuali sistemi software, ci sono due architetture comuni, una per ogni varietà, abbastanza comuni che dovrebbero essere familiari.

Innanzitutto, dato che era la questione, alcuni esempi di sistemi Loosely Coupled:

  • VaxClusters
  • Cluster Linux

Al contrario, alcuni esempi strettamente associati:

  • Sistemi operativi Semetrical-Multi-Processing (SMP) - ad es. Fedora 9
  • CPU multi-thread
  • CPU multi-core

Nel calcolo odierno, esempi di entrambi che operano in un unico sistema complessivo non sono rari. Ad esempio, prendi le moderne CPU Pentium dual o quad core che eseguono Fedora 9: si tratta di sistemi di elaborazione strettamente accoppiati. Quindi, combinane alcuni in un cluster Linux accoppiato liberamente e ora hai in corso sia l'elaborazione informale che strettamente accoppiata! Oh, l'hardware moderno non è meraviglioso!


3

In un linguaggio semplice, accoppiato liberamente significa che non dipende da altri eventi che si verificano. Si esegue in modo indipendente.


1
Questo non è proprio vero - come menzionato in altri esempi, non si tratta tanto della presenza o meno di una relazione tra entità (moduli, classi), ma della possibilità di sostituirle facilmente con altre classi che implementano la stessa funzionalità. ad esempio un ViewModel potrebbe funzionare con diversi modelli, ma sicuramente non funzionerà senza uno
Hayden Crocker,

eh, non molto utile
brgs

2

Alcune risposte lunghe qui. Il principio è molto semplice però. Inoltro la dichiarazione di apertura da Wikipedia :

"L'accoppiamento libero descrive una relazione resiliente tra due o più sistemi o organizzazioni con un qualche tipo di relazione di scambio.

Ogni estremità della transazione rende espliciti i suoi requisiti e fa alcune ipotesi sull'altra estremità. "


1
Se fosse così semplice, non avremmo questa discussione.
brgs

2

Propongo un test molto semplice di accoppiamento del codice :

  1. Il pezzo A di codice è strettamente accoppiato al pezzo B di codice se esiste una possibile modifica al pezzo B che forzerebbe le modifiche nel pezzo A al fine di mantenere la correttezza.

  2. Il pezzo A di codice non è strettamente accoppiato al pezzo B di codice se non ci sono possibili modifiche al pezzo B che renderebbe necessaria una modifica al pezzo A.

Questo ti aiuterà a verificare la quantità di accoppiamento tra i pezzi del tuo codice. per ragionare su questo vedi questo post sul blog: http://marekdec.wordpress.com/2012/11/14/loose-coupling-tight-coupling-decoupling-what-is-that-all-about/


2

Quando si crea un oggetto di una classe utilizzando new parola chiave in un'altra classe, stai effettivamente facendo un accoppiamento stretto (cattiva pratica) invece dovresti usare un accoppiamento libero che è una buona pratica

--- --- A.java

package interface_package.loose_coupling;

public class A {

void display(InterfaceClass obji)
{
    obji.display();
    System.out.println(obji.getVar());
}
}

--- --- B.java

package interface_package.loose_coupling;

public class B implements InterfaceClass{

private String var="variable Interface";

public String getVar() {
    return var;
}

public void setVar(String var) {
    this.var = var;
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Display Method Called");
}
}

--- --- InterfaceClass

package interface_package.loose_coupling;

public interface InterfaceClass {

void display();
String getVar();
}

--- --- MainClass

package interface_package.loose_coupling;

public class MainClass {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    A obja=new A();
    B objb=new B();
    obja.display(objb);     //Calling display of A class with object of B class 

}
}

Spiegazione:

Nell'esempio sopra, abbiamo due classi A e B

La classe B implementa Interface ie InterfaceClass.

InterfaceClass definisce un contratto per la classe B poiché InterfaceClass ha metodi astratti della classe B a cui può accedere qualsiasi altra classe, ad esempio A.

Nella classe A abbiamo un metodo di visualizzazione che può escludere l'oggetto della classe che implementa InterfaceClass (nel nostro caso è la classe B). E su quell'oggetto il metodo di classe A sta chiamando display () e getVar () di classe B

In MainClass abbiamo creato un oggetto di classe A e B. E chiamando il metodo di visualizzazione di A passando l'oggetto di classe B, ovvero objb. Il metodo di visualizzazione di A verrà chiamato con oggetto di classe B.

Ora parlando di accoppiamento libero. Supponiamo che in futuro devi cambiare il nome della Classe B in ABC, quindi non devi cambiarne il nome nel metodo di visualizzazione della classe B, basta creare l'oggetto di nuova (classe ABC) e passarlo al metodo di visualizzazione in MailClass. Non è necessario modificare nulla in Classe A

rif: http://p3lang.com/2013/06/loose-coupling-example-using-interface/


0

Puoi leggere di più sul concetto generico di "accoppiamento libero" .

In breve, è una descrizione di una relazione tra due classi, in cui ciascuna classe conosce il minimo dell'altra e ogni classe potrebbe potenzialmente continuare a funzionare bene se l'altra è presente o meno e senza dipendenza dalla particolare implementazione dell'altra classe.


-8

L'accoppiamento libero, in generale, è rappresentato da 2 attori che lavorano indipendentemente l'uno dall'altro sullo stesso carico di lavoro. Pertanto, se si disponessero di 2 server Web che utilizzano lo stesso database back-end, si direbbe che quei server Web sono accoppiati liberamente. L'accoppiamento stretto sarebbe esemplificato dall'avere 2 processori su un server web ... quei processori sono strettamente accoppiati.

Spero che sia in qualche modo utile.


1
Vedo quello che stai cercando, ma ancora non è un ottimo modo per spiegare che l'accoppiamento stretto è quando due "cose" sono interdipendenti l'una rispetto all'altra, rispetto all'accoppiamento libero quando due "cose" esistono indipendentemente - dove una "cosa" può essere cambiato senza modifiche all'altra "cosa" ...
Bryan Rehbein,

Steve, hai ragione ESATTAMENTE - non meritavi QUALSIASI voto negativo. È solo che il tuo pubblico non era pronto per la tua terminologia e troppi su questo sito hanno l'abitudine di votare ciò che non capiscono o ciò che non ha familiarità. -shrug-
Richard T,

Penso che Steve abbia mancato il punto. L'accoppiamento lento non implica sempre che 2 attori lavorino indipendentemente sullo stesso carico di lavoro.
Rob,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.