Motivo per trattare le variabili e le funzioni di classe interne all'interno di una classe come entità "separate"

1

Nota: esiste una domanda simile che affronta il mio argomento: Stile migliore per le variabili membro ?

... ma quella domanda non affronta "la gestione di un'ampia base di codice legacy e la comprensione di funzioni che sono diventate troppo grandi". Sto cercando la conferma o il rifiuto se la mia situazione lo giustifica essere un buon motivo per adottare una pratica di scrittura di funzioni interne alla classe come se fossero entità separate, con i loro parametri appropriati e valori di ritorno.

La mia domanda

Le variabili interne a una classe sono considerate come scope "globali" all'interno di quella classe. In quanto tali, queste variabili non devono essere incluse esplicitamente come parametri per le funzioni interne della classe. Inoltre, se le funzioni interne restituiscono valori che potrebbero appartenere a variabili esistenti all'interno della classe, anche questi non devono essere restituiti esplicitamente. Puoi semplicemente fare riferimento a loro tramite this oggetto. Ma sta facendo una buona pratica?

La mia domanda viene dal contesto del refactoring di un enorme codice di base legacy. In quanto tale, quando vedo una funzione all'interno di una classe che va come $this->IamACute3000LineFunctionDoingInsanelyCuteStuffInASpaghettiCodeLikeWay() , ho poca idea di quali variabili "globali" della classe debbano fare il suo lavoro e cosa restituisca esattamente. Ciò rende difficile e dispendioso in termini di tempo occuparsi di quel codice quando qualsiasi lavoro deve essere fatto sulla classe. Quindi, anche se potrebbe non avere senso all'interno della classe stessa, vedo dei meriti nello scrivere codice come sotto, trattando variabili e parametri come se la funzione fosse scritta per essere usata al di fuori della classe stessa:

class HelloClass
{
   $private $name;
   $private $greeting;

   public function __construct($name)
   {
       $this->name = $name;

       //line of interest
       $this->greeting = $this->prepGreeting($this-name);
   }

   //function of interest
   private function prepGreeting($name)
   {
      return "Hello, $name";
   }

   public function getGreeting()
   {
       return $this->greeting;
   }
}

$sayHello = new HelloClass("Dennis");
print $sayHello->getGreeting();

Qui, prepGreeting è la funzione in questione. Sicuramente, sembra un po 'ridicolo ... poiché a malapena si avvale di meccanismi di classe integrati, se non del tutto. Può essere invece riscritto come tale (con opportune altre modifiche del costruttore, che non sono mostrate):

   private function prepGreeting()
   {
      $this->greeting = "Hello, " . $this->name;
   }

Ma in realtà devi leggere il corpo della funzione per capire cosa fa, cosa tocca e cosa restituisce.

La mia domanda è questa :

nel mio esempio, in cui sto trattando un codice di grandi dimensioni in cui la comprensione di una funzione richiede tempo, penso che ci sia una buona ragione per scrivere le funzioni di classe interne come se fossero separate, non appartenenti alla classe, poiché sarà superiore per capire cosa succede all'interno della funzione e cosa restituisce. Questa funzione sarà autonoma e, come tale, aiuterà molto con il refactoring. Potrei cogliere quella funzione, piegare il modo in cui ne ho bisogno per piegarla, spostarla in un'altra classe, se necessario, rendendo così più facile lavorare con la classe stessa. Ma, in generale, consiglieresti questa pratica di scrittura delle funzioni durante la scrittura / progettazione di classi?

Oppure consiglieresti invece di usare l'oggetto this incorporato, trattando le variabili di classe interne come "classi globali", anche se ciò potrebbe avere un impatto sulla leggibilità / comprensione / comprensione della funzione se le sue dimensioni crescono, come spesso accade nei progetti di vita reale?

Infine, mi mancano punti più importanti mentre mi concentro su questo specifico problema di scrittura-stile?

Add-on

Vedo il merito forse nell'utilizzare una via di mezzo, dove i parametri di funzione non sono passati alla funzione (la funzione usa this oggetto per arrivare a quelli), ma la funzione restituisce comunque valori, invece di aggiornare this oggetto direttamente, e spetta al chiamante aggiornare la variabile this . cioè questo cambierà la mia "linea di interesse" con questo codice: $this->greeting = $this->prepGreeting(); e almeno saprò cosa dovrebbe restituire la funzione, a colpo d'occhio.

    
posta Dennis 08.05.2014 - 19:46
fonte

3 risposte

2

"Quando vedo una funzione all'interno di una classe, yada yada ..." Penso che la parte importante da ricordare qui è che la funzione è all'interno della classe. Tutte le funzionalità rilevanti sono quindi confinato con nella classe ("incapsulamento"). Il tuo uso delle parole "globale all'interno della classe" non è veramente rilevante, a tale riguardo.

Tutti i linguaggi sensati agli oggetti funzionano in questo modo; si aspettano che tu sia in grado di gestire i membri interni della classe in modo soddisfacente, purché i dettagli interni della classe non trapelino. Se lavorare con i membri interni di una classe è diventato difficile, significa che la classe è diventata troppo grande e troppo complessa. Probabilmente ha bisogno di essere diviso in classi più piccole.

    
risposta data 08.05.2014 - 21:38
fonte
1

Come parte dei tuoi sforzi di refactoring, è molto utile incapsulare le funzioni in modo che eseguano la loro funzione con i soli parametri passati.

Riduce l'accoppiamento. In una grande (specialmente in una grande) classe, con molti campi, devi considerarli globali, soprattutto perché la loro accessibilità e possibilità di cambiamento non sono locali per lo schermo che vedi di fronte a te o il metodo che vedi in di fronte a te. Passare dalla condivisione delle "variabili globali" ai parametri di passaggio è un miglioramento sostanziale.

Se riesci a ridurre o rimuovere gli effetti collaterali mentre ci sei, affronta un aspetto simile di accoppiamento. La funzione restituisce solo un valore o chiama solo un metodo esterno che non dipende dalla classe host e non è più necessario gestire i globali nello stesso modo.

    
risposta data 09.05.2014 - 15:25
fonte
0

Finally, am I missing any greater points while focusing on this specific function-writing-style issue?

Sì.

Dai suoni di esso le classi sono molto grandi. Modo in cui grande. Se non riesci a capire cosa sta facendo un metodo privato solo guardandolo, o quali variabili private vengono chiamate e per cosa sono utilizzate, è un odore di codice serio che le tue classi sono troppo grandi e non focalizzate .

Dovrebbe essere ovvio dal metodo privato che sta aggiornando lo stato dell'oggetto, e l'oggetto dovrebbe avere così poco stato che dovrebbe essere ovvio cosa significa dire che il suo stato è in fase di aggiornamento. Se hai un oggetto che ha una tonnellata di stato che può essere cambiato in modi diversi e non sai mai quale sottosezione dello stato un metodo sta per alterare, di nuovo i tuoi oggetti sono troppo grandi.

Naturalmente potresti non essere in grado di controllarlo se è un codice legacy che hai ereditato. Ma piuttosto che rivedere i metodi avrebbe più senso rompere le classi stesse. Anche la tua classe sopra può essere suddivisa in una classe Nome e una classe Saluto, nel qual caso lo stato degli oggetti diventa più chiaro (una classe Nome ha semplicemente il nome, una classe Saluto ha semplicemente il saluto)

    
risposta data 09.05.2014 - 12:12
fonte

Leggi altre domande sui tag