Quando i metodi di disaccoppiamento non sono una buona idea?

1

È una discussione su seguire molto rigorosamente l'SRP (Single Responsability Principle) vs. essere più flessibile quando si scrivono codici semplici, come l'impostazione o il recupero dei valori delle proprietà, anche fuori da un contesto diretto.

Il mio primo dubbio riguarda dove deve essere incluso SRP. Ho sempre letto che SRP dovrebbe essere applicato alle lezioni. Ma e su metodi, proprietà o tratti ( come in PHP ), ...?

Se questa risposta è no , forse possiamo eliminare tutto il testo di seguito.

Per esemplificare , definiamo un caso di esempio. Per comprendere più facilmente , scriveremo una struttura singleton per una classe chiamata Example . Ignora IoC, in questo caso.

Dovrebbe avere due metodi, in pratica:

  • getInstance() : restituisce un'istanza univoca della tua classe; e
  • rebuildInstance() : distruggerà solo l'istanza corrente e la ricreerà;

Fondamentalmente per il suo funzionamento, getInstance() dovrebbe controllare se l'istanza interna è stata impostata, crearla in caso contrario, quindi restituirla. E rebuildInstance() dovrebbe distruggere l'istanza corrente se è stata definita e creare una nuova, senza restituire nulla.

Rendiamolo più visivo ( in qualche pseudo-lingua ):

class Example 
{
    static private Example instance;

    static public Example getInstance() 
    {
        if (!this.instance) 
        {
            this.instance = new Example;
        }

        return this.instance;
    }

    static public void rebuildInstance() 
    {
        if (this.instance)
        {
            destroy(this.instance);
        }

        this.instance = new Example;
    }
}

Quindi nota che:

  • getInstance() ha due responsabilità: 1. verifica e istanzia; 2. ritorno.
  • rebuildInstance() ha due responsabilità: 1. controllare e distruggere; 2. istanziare;

Vedrai che entrambi dovrebbero creare un'istanza, quindi consideralo come una duplicazione di effetti . Per evitare ciò, dovrei disaccoppiare i miei metodi in modo che ognuno abbia una singola responsabilità, quindi ho bisogno di creare altri due metodi:

  • buildInstanceWhenNeed() ;
  • destroyInstanceWhenNeed();

Diventerà più chiaro ciò che ciascun metodo fa per nome e per struttura. Quindi il nostro codice sembrerà:

class Example 
{
    static private Example instance;

    static private void buildInstanceWhenNeed() 
    {
        if (!this.instance) 
        {
            this.instance = new Example;
        }
    }

    static public Example getInstance() 
    {
        self.buildInstanceWhenNeed();

        return this.instance;
    }

    static private void destroyInstanceWhenNeed()
    {
        if (this.instance)
        {
            destroy(this.instance);
        }
    }

    static public void rebuildInstance() 
    {
        self.destroyInstanceWhenNeed();
        self.buildInstanceWhenNeed();
    }
}

Va bene.

Sembra che ora stia rispettando completamente l'SRP sui metodi, molto rigorosamente . Ogni metodo ha una singola responsabilità senza ottenere la responsabilità della classe. Tranne il fatto che ha un pattern singleton al suo interno, ma ho detto di ignorare l'uso di IoC all'inizio del topic.

Così ora ho altre domande:

  1. Devo applicare SRP ai metodi, disaccoppiandolo, per assicurarmi che abbia una singola responsabilità su ciascun metodo?
  2. Se sì. Devo farlo anche quando il metodo non duplica alcun effetto? Ad esempio: se rebuildInstance() non esiste qui, quindi non ho bisogno di disaccoppiare getInstance() perché è l'istanza unica che, di fatto, creerà una nuova istanza di classe. Quindi, in questo caso, ho ancora bisogno di creare buildInstanceWhenNeed() o no?
  3. Se sì, ma priorità più bassa. E a proposito delle prestazioni? Voglio dire, quando veramente influisce sul tempo di esecuzione, diminuendo considerevolmente la velocità dell'applicazione a causa dei metodi ultra disaccoppiati ( che forse interessa solo le lingue interpretate ), ma con specifiche elevate per ciascuno uno.
posta David Rodrigues 25.01.2016 - 19:18
fonte

2 risposte

6

Consentimi di dedicarti allo Zen:

Per favore non incorrere in paralisi delle analisi .

Da quel ragionamento potresti anche chiamare il tuo metodo destroyInstanceWhenNeededButOnlyIfYouCallMe() .

Una singola riga di codice comune tra due metodi, specialmente un'istanza, non è un prurito che deve essere graffiato. SRP non entra in quella minuzie. Riguarda le classi che fanno troppo o hanno più di una ragione per cambiare.

Il design originale è OK. Il secondo design è troppo pensante per un così scarso guadagno.

    
risposta data 26.01.2016 - 08:25
fonte
3

Il principio di responsabilità unica è in definitiva un principio di progettazione creato per garantire che "una classe debba avere solo una ragione per cambiare". Anche se questo non significa che non può applicare ai metodi, significa che è più strettamente applicabile alle classi.

Nel determinare la responsabilità della tua classe o metodo, è importante considerare il consumatore della tua classe o metodo. Chi / cosa userà questa classe e qual è il suo scopo? La tua classe è un modulo del livello aziendale progettato per coordinare attività aziendali complesse? la tua classe è una classe di persistenza progettata per inviare dati al tuo modulo di persistenza? I consumatori di queste classi e le attività previste forniranno spesso un suggerimento sull'opportunità o meno che la tua classe stia facendo troppo.

Per questo motivo il tuo esempio non è chiaro. Chi userà Esempio? Cosa fa l'esempio? Se non hai definito cosa fa realmente e chi / cosa è, come puoi dire se fa troppo?

Esaminando i tuoi metodi specifici, credo che inizi a toccare temi diversi da Principio di responsabilità singola . Prima di tutto, la tua API è difettosa mentre esponi tutti i tuoi metodi come pubblici. Credo che destroyInstanceWhenNeeded() e buildInstanceWhenNeed() debbano essere private.

Con quello risolto puoi considerare i tuoi metodi individuali. Dovrebbe esserci buildInstanceWhenNeeded() ? Forse, ma è più un problema di Non ripeti te stesso . Dovrebbe esserci destroyInstanceWhenNeeded() ? Questo è soggettivo in base a una serie di fattori. Migliora la leggibilità di rebuildInstance() ? Autocodifica alcuni comportamenti o algoritmi non ovvi richiesti in rebuildInstance() ?

Come puoi vedere, c'è molto da considerare qui. Per rispondere alle tue domande:

  1. Should I apply SRP on methods, decoupling it, to make sure that it have a single responsibility on each method?

Soggettivamente sì se migliora effettivamente la leggibilità del codice, se il metodo disaccoppiato incapsula la logica che non si riferisce direttamente al metodo basato sul suo nome di firma, o se aiuta la logica dell'autodocumentazione che potrebbe altrimenti richiedere un commento

  1. If yes. Should I do it even when the method don't duplicate any effect? For instance: if rebuildInstance() doesn't exists here, then I don't need decouple getInstance() because is the unique instance that will, in fact, create a new instance of class. So in this case, do I still need create buildInstanceWhenNeed() or not?

Anche in questo caso, è difficile dire in base ai problemi relativi al tuo esempio per quanto riguarda il consumatore della tua classe, ma ti ho fornito motivi che vanno oltre la duplicazione degli sforzi per il refactoring di un metodo.

  1. If yes, but lower priority. And about performance? I mean, when it really affect the runtime, decreasing considerably the speed of application because of ultra decoupled methods (which perhaps only affects interpreted languages), but with high specifications to each one.

Se le tue chiamate al metodo sono così specifiche che stai riscontrando problemi di prestazioni con lo stack, potresti aver commesso un errore lungo il percorso.

    
risposta data 25.01.2016 - 22:47
fonte

Leggi altre domande sui tag