Risposte:
Lo stretto accoppiamento avviene quando un gruppo di classi dipende fortemente l'uno dall'altro.
Questo scenario si presenta quando una classe si assume troppe responsabilità o quando una preoccupazione è ripartita su più classi anziché avere una propria classe.
L'accoppiamento allentato si ottiene mediante un design che promuove la responsabilità individuale e la separazione delle preoccupazioni.
Una classe liberamente accoppiata può essere consumata e testata indipendentemente da altre classi (concrete).
Le interfacce sono un potente strumento da utilizzare per il disaccoppiamento. Le classi possono comunicare attraverso interfacce piuttosto che altre classi concrete, e qualsiasi classe può trovarsi dall'altra parte di quella comunicazione semplicemente implementando l'interfaccia.
Esempio di accoppiamento stretto:
class CustomerRepository
{
private readonly Database database;
public CustomerRepository(Database database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
class Database
{
public void AddRow(string Table, string Value)
{
}
}
Esempio di accoppiamento libero:
class CustomerRepository
{
private readonly IDatabase database;
public CustomerRepository(IDatabase database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
interface IDatabase
{
void AddRow(string Table, string Value);
}
class Database implements IDatabase
{
public void AddRow(string Table, string Value)
{
}
}
Un altro esempio qui .
Il cappello è "liberamente accoppiato" al corpo. Ciò significa che puoi toglierti facilmente il cappello senza apportare modifiche alla persona / al corpo. Quando puoi farlo, allora hai "accoppiamento libero". Vedi sotto per l'elaborazione.
Pensa alla tua pelle. È bloccato sul tuo corpo. Si adatta come un guanto. E se volessi cambiare il colore della tua pelle da dire bianco a verde? Riesci a immaginare quanto sarebbe doloroso staccare la pelle, tingerla e poi incollarla di nuovo ecc? Cambiare la pelle è difficile perché è strettamente accoppiato al tuo corpo. Non puoi apportare modifiche facilmente. Dovresti fondamentalmente ridisegnare un essere umano per renderlo possibile.
Dio non era un buon programmatore orientato agli oggetti.
Ora pensa a vestirti la mattina. Non ti piace il blu? Nessun problema: puoi indossare una camicia rossa. Puoi farlo facilmente e senza sforzo perché la maglietta non è realmente collegata al tuo corpo allo stesso modo della tua pelle. La maglietta non sa né si preoccupa del corpo che sta succedendo . In altre parole, puoi cambiare i tuoi vestiti, senza cambiare davvero il tuo corpo.
Questo è il concetto di base in breve.
È importante perché il software cambia continuamente. In generale, vuoi essere in grado di modificare facilmente il tuo codice, senza cambiare il tuo codice. So che suona come un ossimoro, ma per favore abbi pazienza con me.
Esempi CSV / JSON / DB: se qualcuno desidera il proprio output in un file CSV anziché JSON ecc., O se si desidera passare da MySQL a PostGreSQL, si dovrebbe essere in grado di apportare queste modifiche estremamente facilmente nel proprio codice, senza dover riscrivere l'intera classe ecc. In altre parole, non si desidera accoppiare strettamente l'applicazione con un'implementazione specifica del database (ad es. Mysql) o ad un output particolare (ad es. file CSV). Perché, come è inevitabile nel software, arriveranno cambiamenti. Quando arrivano, è molto più semplice se le parti del tuo codice sono accoppiate liberamente.
Esempio di ricambi auto: se qualcuno vuole la propria auto in nero , non è necessario riprogettare l'intera auto per farlo. Un'auto e i suoi pezzi di ricambio sarebbero un esempio perfetto di un'architettura liberamente accoppiata. Se vuoi sostituire il tuo motore con uno migliore, dovresti essere in grado di rimuovere semplicemente il tuo motore senza troppi sforzi e sostituirlo con uno migliore. Se la tua auto funziona solo con motori Rolls Royce 1234 e nessun altro motore, la tua auto sarà strettamente accoppiata a quel motore (Rolls Royce 1234). Sarebbe meglio se cambiassi il design della tua auto in modo che funzionasse con qualsiasimotore, in modo che sia un po 'più liberamente accoppiato con i suoi componenti. Ancora meglio sarebbe se la tua auto potesse funzionare senza bisogno di un motore! Sta per succedere una certa quantità di accoppiamento, ma dovresti lavorare per minimizzarlo il più possibile. Perché? Perché quando cambiano i requisiti dovremmo essere ancora in grado di fornire software di buona qualità, molto rapidamente e siamo aiutati in questo obiettivo da un accoppiamento lento.
In breve, l'accoppiamento lento facilita la modifica del codice. Le risposte sopra forniscono un codice che vale la pena leggere a questo punto.
Ri: @TimoHuovinen commenta - il concetto di accoppiamento libero va di pari passo con i concetti di polimorfismo. Se afferri l'analogia di base di una camicia / parti di automobili, sarai pronto a dare un senso al polimorfismo. Il modo migliore, a questo punto, è leggere gli esempi di codice forniti dai miei stimabili colleghi nelle altre risposte su questo thread. Se dico di più potresti essere sovraccarico di troppe informazioni.
Nella progettazione orientata agli oggetti, la quantità di accoppiamento si riferisce a quanto la progettazione di una classe dipende dalla progettazione di un'altra classe. In altre parole, con quale frequenza i cambiamenti nella classe A cambiano in classe B? L'accoppiamento stretto significa che le due classi cambiano spesso insieme, l'accoppiamento lento significa che sono per lo più indipendenti. In generale, si consiglia un accoppiamento lento perché è più facile da testare e mantenere.
Puoi trovare utile questo documento di Martin Fowler (PDF) .
In generale, l'accoppiamento stretto è negativo ma il più delle volte, poiché riduce la flessibilità e la riutilizzabilità del codice, rende le modifiche molto più difficili, impedisce la testabilità ecc.
Tightly Coupled Object è un oggetto che necessita di conoscere un po 'l'uno dell'altro e di solito dipendono fortemente l'uno dall'altro. La modifica di un oggetto in un'applicazione strettamente accoppiata spesso richiede la modifica di numerosi altri oggetti. In piccole applicazioni possiamo facilmente identificare le modifiche e ci sono meno possibilità di perdere qualcosa. Ma in applicazioni di grandi dimensioni queste interdipendenze non sono sempre note a tutti i programmatori o è probabile che manchino cambiamenti. Ma ogni insieme di oggetti liberamente accoppiati non dipende dagli altri.
In breve, possiamo dire che l'accoppiamento libero è un obiettivo di progettazione che cerca di ridurre le interdipendenze tra i componenti di un sistema con l'obiettivo di ridurre il rischio che i cambiamenti in un componente richiedano cambiamenti in qualsiasi altro componente. L'accoppiamento libero è un concetto molto più generico inteso ad aumentare la flessibilità di un sistema, renderlo più gestibile e rendere l'intero quadro più "stabile".
L'accoppiamento si riferisce al grado di conoscenza diretta che un elemento ha di un altro. possiamo dire un esempio: A e B, solo B cambia il suo comportamento solo quando A cambia il suo comportamento. Un sistema liberamente accoppiato può essere facilmente suddiviso in elementi definibili.
Quando due oggetti sono liberamente accoppiati, possono interagire ma si conoscono ben poco.
I progetti liberamente accoppiati ci consentono di costruire sistemi OO flessibili in grado di gestire il cambiamento.
Il modello di progettazione di Observer è un buon esempio per creare classi liberamente accoppiate, puoi dargli un'occhiata su Wikipedia .
Un estratto dal mio post sul blog sull'accoppiamento:
Che cos'è l' accoppiamento stretto : -
Come sopra la definizione precedente, un oggetto strettamente accoppiato è un oggetto che deve conoscere altri oggetti e di solito sono fortemente dipendenti dalle reciproche interfacce.
Quando cambiamo un oggetto in un'applicazione strettamente accoppiata, spesso richiede modifiche ad un numero di altri oggetti. Non ci sono problemi in una piccola applicazione che possiamo facilmente identificare la modifica. Ma nel caso di applicazioni di grandi dimensioni queste interdipendenze non sono sempre note a tutti i consumatori o ad altri sviluppatori o ci sono molte possibilità di cambiamenti futuri.
Prendiamo un codice demo del carrello per capire l'accoppiamento stretto:
namespace DNSLooseCoupling
{
public class ShoppingCart
{
public float Price;
public int Quantity;
public float GetRowItemTotal()
{
return Price * Quantity;
}
}
public class ShoppingCartContents
{
public ShoppingCart[] items;
public float GetCartItemsTotal()
{
float cartTotal = 0;
foreach (ShoppingCart item in items)
{
cartTotal += item.GetRowItemTotal();
}
return cartTotal;
}
}
public class Order
{
private ShoppingCartContents cart;
private float salesTax;
public Order(ShoppingCartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float OrderTotal()
{
return cart.GetCartItemsTotal() * (2.0f + salesTax);
}
}
}
Problemi con l'esempio sopra
L'accoppiamento stretto crea alcune difficoltà.
Qui, i OrderTotal()
metodi ci danno un importo completo per gli articoli correnti dei carrelli. Se vogliamo aggiungere le funzionalità di sconto in questo sistema di carrello. È molto difficile da fare nel codice sopra perché dobbiamo fare cambiamenti in ogni classe poiché è strettamente accoppiato.
L'accoppiamento lento significa che il grado di dipendenza tra due componenti è molto basso.
Esempio: SIM GSM
L'accoppiamento stretto significa che il grado di dipendenza tra due componenti è molto elevato.
Esempio: CDMA Mobile
Il modo in cui lo capisco è che l'architettura strettamente accoppiata non offre molta flessibilità per il cambiamento rispetto all'architettura liberamente accoppiata.
Ma nel caso di architetture liberamente accoppiate, formati di messaggi o piattaforme operative o revamping, la logica aziendale non influisce sull'altra estremità. Se il sistema viene rimosso per un rinnovamento, ovviamente l'altra estremità non sarà in grado di accedere al servizio per un po ', ma a parte questo, l'estremità invariata può riprendere lo scambio di messaggi com'era prima del rinnovamento.
L'accoppiamento stretto significa che una classe dipende da un'altra classe.
Loose Coupling significa che una classe dipende dall'interfaccia piuttosto che dalla classe.
In accoppiamento stretto , ci sono la dipendenza hardcoded dichiarato nei metodi.
In accoppiamento libero , dobbiamo passare la dipendenza esternamente in fase di esecuzione anziché codificata. (I sistemi di coppie allentate usano l'interfaccia per una minore dipendenza dalla classe.)
Ad esempio, abbiamo un sistema che può inviare output in due o più modi come output JSON, output CSV, ecc.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput() {
// Here Output will be in CSV-Format, because of hard-coded code.
// This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
// Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
OutputGenerator outputGenerator = new CSVOutputGenerator();
output.generateOutput();
}
}
Nell'esempio sopra, se vogliamo cambiare l'output in JSON, allora dobbiamo trovare e cambiare l'intero codice, perché Class1 è strettamente accoppiato con la classe CSVOutputGenerator.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput(OutputGenerator outputGenerator) {
// if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
// if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)
// Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
// Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
OutputGenerator outputGenerator = outputGenerator;
output.generateOutput();
}
}
Ci sono alcuni strumenti che forniscono l'iniezione delle dipendenze attraverso la loro libreria, ad esempio in .net abbiamo ninject Library .
Se stai andando oltre in Java, Spring offre queste funzionalità.
È possibile creare oggetti liberamente accoppiati introducendo interfacce nel codice, ecco cosa fanno queste fonti.
Di 'nel tuo codice che stai scrivendo
Myclass m = new Myclass();
ora questa affermazione nel tuo metodo dice che sei dipendente da myclass
questo è chiamato strettamente accoppiato. Ora fornisci l'iniezione del costruttore, o l'iniezione di proprietà e l'oggetto di istanza, quindi diventerà vagamente accoppiato.
Ci sono molte belle risposte qui usando analogie ma un amico al lavoro mi ha dato un esempio che mi è piaciuto di più di tutte quelle menzionate qui ... Occhi e occhiali!
Accoppiamento stretto
L'accoppiamento stretto sarebbe gli occhi. Se voglio sistemare la mia vista, è molto costoso sottoporsi a un trapianto di occhi e comporta un discreto rischio. E se il designer (essendo la razza umana) trovasse un modo migliore. Aggiungi una funzione che è liberamente accoppiata al corpo in modo che possa essere facilmente cambiata! (sì .. occhiali)
Accoppiamento lasco
Posso facilmente sostituire i miei occhiali senza rompere la visione sottostante. Posso togliermi gli occhiali e la mia visione sarà come prima (non migliore o peggiore). L'uso di diverse paia di occhiali cambia il modo in cui vediamo il mondo attraverso i nostri occhi con pochi rischi e facile manutenibilità.
Sommario
Quindi la prossima volta qualcuno ti chiede "a chi importa se il mio codice è strettamente accoppiato?" La risposta riguarda gli sforzi per cambiare, gli sforzi per mantenere e il rischio di cambiamento.
Quindi, come si fa in C #? Iniezione di interfacce e dipendenze!
MODIFICARE
Questo è anche un buon esempio del modello Decorator, in cui gli occhi sono la classe che stiamo decorando soddisfacendo i requisiti dell'interfaccia ma dando diverse funzionalità (ad esempio occhiali da sole, occhiali da lettura, lenti d'ingrandimento per gioiellieri ecc.)
L'accoppiamento lento è e la risposta a dipendenze hardcoded vecchio stile e problemi correlati come la frequente ricompilazione quando qualcosa cambia e il riutilizzo del codice. Sottolinea l'implementazione della logica di lavoro nei componenti e di evitare il codice di cablaggio specifico della soluzione lì.
Accoppiamento allentato = IoC Vedere questo per una spiegazione più semplice.
Loose Coupling è il processo di dare indirettamente la dipendenza di cui la tua classe ha bisogno senza fornire tutte le informazioni della dipendenza (cioè nell'interfaccia from) nel caso in cui l'accoppiamento stretto dia direttamente nella dipendenza che non è un buon modo di codificare.
Riguarda il tasso di dipendenza delle classi da un altro che è così basso in accoppiamento lento e così alto in accoppiamento stretto. Per essere chiari nell'architettura di orientamento del servizio , i servizi sono vagamente accoppiati tra loro contro il monolitico che la dipendenza delle classi tra loro è di proposito
Se la creazione / esistenza di un oggetto dipende da un altro oggetto che non può essere personalizzato, il suo accoppiamento stretto. E, se la dipendenza può essere adattata, il suo accoppiamento lento. Considera un esempio in Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
Il client di Car
classe può crearne uno con SOLO motore "X_COMPANY".
Valuta la possibilità di interrompere questo accoppiamento con la possibilità di cambiarlo:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Ora, a Car
non dipende da un motore di "X_COMPANY" in quanto può essere creato con tipi.
Una nota specifica di Java: l' uso delle interfacce Java solo per il disaccoppiamento, non è un approccio corretto. In Java, un'interfaccia ha uno scopo: agire come un contratto che fornisce intrisicamente comportamento / vantaggio di disaccoppiamento.
Il commento di Bill Rosmus nella risposta accettata ha una buona spiegazione.
L'accoppiamento stretto significa che le classi e gli oggetti dipendono l'uno dall'altro. In generale, l'accoppiamento stretto di solito non è buono perché riduce la flessibilità e la riutilizzabilità del codice, mentre l'accoppiamento allentato significa ridurre le dipendenze di una classe che utilizza direttamente la diversa classe.
Accoppiamento stretto L'oggetto strettamente accoppiato è un oggetto che deve conoscere altri oggetti e di solito dipende fortemente dalle reciproche interfacce. La modifica di un oggetto in un'applicazione strettamente accoppiata spesso richiede la modifica di numerosi altri oggetti. Nelle piccole applicazioni, possiamo facilmente identificare le modifiche e ci sono meno possibilità di perdere qualcosa. Ma nelle applicazioni di grandi dimensioni, queste interdipendenze non sono sempre note a tutti i programmatori e c'è una possibilità di trascurare i cambiamenti. Esempio:
class A {
public int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
System.out.println("aObject.a value is: " + aObject.a);
}
}
In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.
Output
aObject.a value is: 100
Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:
class A {
private int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.setA(100); // No way to set 'a' to such value as this method call will
// fail due to its enforced rule.
System.out.println("aObject value is: " + aObject.getA());
}
}
Nell'esempio sopra, il codice definito da questo tipo di implementazione utilizza un accoppiamento libero ed è consigliato poiché la classe B deve passare attraverso la classe A per ottenere il suo stato in cui vengono applicate le regole. Se la classe A viene modificata internamente, la classe B non si interromperà poiché utilizza solo la classe A come mezzo di comunicazione.
Output
getA() method
aObject value is: 0