Uno dei principali vantaggi del basso accoppiamento è che riduce il numero di cose da considerare simultaneamente per comprendere un singolo componente di un sistema, consentendo tra l'altro di semplificare il debugging, semplificare la manutenzione e migliorare l'estendibilità. Un modo ragionevole per rispondere alla tua domanda è considerare se SRP possa migliorare il tuo codice rispetto a questi parametri.
La mia affermazione è che SRP ha la capacità di ridurre l'accoppiamento , ma che l'accoppiamento ridotto non è garantito. Illustrerò questo con due scenari.
Scenario 1 (non farlo)
- Inizia con una mega funzione
foo()
.
- Tieni presente che
foo()
viola SRP, quindi ridimensionalo in bar()
e baz()
.
- Man mano che la tua applicazione cresce, altre parti del codice finiscono a seconda di
bar()
e baz()
.
- I clienti e i casi d'uso cambiano nel tempo, quindi alla fine
foo()
ha bisogno di una modifica. La maggior parte della logica in foo()
è implementata in bar()
e baz()
, quindi per cambiare comportamento in foo()
cambiamo il comportamento in bar()
e baz()
invece .
- Ora tutto si rompe.
Anche se SRP ha la capacità di ridurre l'accoppiamento (almeno lo sto affermando), in questo esempio il programmatore sta trattando foo()
, bar()
e baz()
come una singola unità E hanno il complessità aggiuntiva di tale unità che viene suddivisa tra più definizioni di funzioni e forse anche più file. L'SRP era solo di nome e non aveva reali vantaggi a causa del modo in cui venivano utilizzate le funzioni.
Scenario 2 (accoppiamento ridotto con SRP)
- Inizia con una mega funzione
foo()
.
- Tieni presente che
foo()
viola SRP, quindi ridimensiona in bar()
e baz()
.
- Man mano che la tua applicazione cresce, altre parti del codice finiscono a seconda di
bar()
e baz()
.
- Alla fine
foo()
ha bisogno di una modifica, ma non abbiamo un componente di basso livello appropriato in giro con la funzionalità desiderata, quindi facciamo una nuova funzione bizz()
.
- Ora
foo()
è composto da bar()
e bizz()
, e tutto il resto funziona ancora.
In questo esempio, è facile ragionare sul comportamento di foo()
perché trattiamo le sue due parti costitutive come atomico . Hanno un comportamento ben definito e combinati costituiscono foo()
. Quando tali comportamenti sono insufficienti, creiamo un nuovo componente atomico con la funzionalità desiderata. Questo approccio porta facilmente al riutilizzo del codice e impedisce modifiche all'API. Inoltre, tutti i componenti sono abbastanza piccoli e possono essere facilmente ragionati e dimostrati come corretti.
Extra: Anche se SRP può ridurre l'accoppiamento in un certo senso, se le funzioni non sono raggruppate in modo appropriato, ha la possibilità di avere ogni modulo in un'applicazione in un modo o nell'altro in ogni altro modulo. La progettazione dell'intero sistema da accoppiare liberamente è tanto importante quanto la progettazione di funzioni da accoppiare liberamente, e per approssimativamente le stesse ragioni.