È una tecnica scadente avere funzioni all'interno di una classe che dipendono l'una dall'altra in modo "a cascata"?

5

Sono abbastanza nuovo in PHP e OOP. Detto questo, volevo sapere come le funzioni indipendenti dovrebbero essere all'interno di una classe. So che ogni funzione dovrebbe essere responsabile di fare solo una cosa. Tuttavia, come puoi vedere nella mia classe di seguito, di tanto in tanto mi trovo a creare funzioni che si basano l'una sull'altra in un modo tipo "a cascata".

Questa è una buona pratica? C'è un modo diverso in cui dovrei strutturare questa classe / questi tipi di funzioni? Voglio assicurarmi di sviluppare buone abitudini.

Grazie in anticipo per il tuo aiuto.

class PubMedQuery {

private $query;
private $searchParameters;
private $searchURL;
private $fetchParameters;
private $fetchURL;
private $searchResults;
private $fetchResults;
private $matches;
private $matchRegex;
private $emailAddresses;

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

public function setSearchParameters() {
    $this->searchParameters = array(
        'db'         => 'pubmed',
        'term'       => $this->query,
        'retmode'    => 'xml',
        'retstart'   => '0',
        'retmax'     => '1000',
        'usehistory' => 'y'
    );
}

public function getSearchParameters() {
    return $this->searchParameters; 
} 

public function setFetchParameters() {
    $this->fetchParameters = array(
        'db'        => 'pubmed',
        'retmax'    => '1000',
        'query_key' => (string) $this->searchResults->QueryKey,
        'WebEnv'    => (string) $this->searchResults->WebEnv
    );
}

public function getFetchParameters() {
    return $this->fetchParameters; 
} 

public function setSearchURL() {
    $this->baseSearchURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils /esearch.fcgi?';
    $this->searchURL = $this->baseSearchURL . http_build_query($this->getSearchParameters());
}

public function getSearchURL() {
    return $this->searchURL; 
}

public function setFetchURL() {
    $this->baseFetchURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?';
    $this->fetchURL = $this->baseFetchURL . http_build_query($this->getFetchParameters());
}

public function getFetchURL() {
    return $this->fetchURL; 
}

public function setSearchResults() {
    $this->setSearchParameters();  
    $this->setSearchURL();
    $this->searchResults = simplexml_load_file($this->getSearchURL());
}

public function getSearchResults() {
    $this->setFetchParameters();
    $this->setFetchURL();
    return file_get_contents($this->getFetchURL()); 
}

public function setEmailAddresses() {
    $this->matches = array();
    $this->matchRegex = '/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/'; 
    preg_match_all($this->matchRegex, $this->getSearchResults(), $this->matches);
    $this->emailAddresses = array_unique(array_values($this->matches[0]));
}

public function getEmailAddresses() {
    $this->setSearchResults();
    $this->getSearchResults();
    $this->setEmailAddresses();
    return $this->emailAddresses;
}
}

//Example using search term "psoriasis"
$query  = new PubMedQuery('psoriasis');
echo implode('<br />', $query->getEmailAddresses());
    
posta LookingForHelpWithArray 21.10.2011 - 16:40
fonte

2 risposte

6

Ciò che hai sembra buono.

Hai diverse azioni setEmailAddresses , getEmailAddresses ciascuna delle quali comprende una serie di passaggi. Alcuni di questi passaggi sono comuni a più azioni, quindi è perfettamente logico includerli nei propri metodi.

La parte restante dell'azione potrebbe essere codificata nel metodo di livello superiore, ma averlo nel proprio "metodo secondario" non è un problema - in effetti si potrebbe dire che è una pratica migliore in quanto si mantiene responsabile ciascun metodo solo una cosa.

    
risposta data 21.10.2011 - 16:47
fonte
2

Per rispondere alla tua domanda, no, non è affatto una cattiva pratica dividere gli interni di una classe in più metodi come hai fatto qui. Come hanno detto le altre risposte e commenti, è in realtà una buona pratica.

Sei sulla strada giusta, ma ho visto un paio di cose che penso abbiano bisogno di attenzione. Dall'esempio fornito all'esterno della definizione della classe, sembra che l'uso principale di oggetti derivati da questa classe sia (approssimativamente) per estrarre gli indirizzi email da una query PubMed. Hai diviso le attività generali necessarie per farlo in tutta la classe in modo appropriato; tuttavia, molti di questi compiti si limitano a impostare alcune informazioni immutabili. Fai questo tipo di metodi, ad es. setSearchParameters (), ha davvero bisogno di essere accessibile al di fuori della classe? Direi che no, non lo fanno, perché la maggior parte di questi metodi non fa altro che ottenere o impostare variabili dei membri privati.

Espongo l'intero problema di incapsulamento perché un modo in cui potresti migliorare il tuo codice sarebbe quello di eliminare alcune delle variabili dei membri private a meno che tu non ne abbia assolutamente bisogno. Non conosco i requisiti del tuo progetto, ma mi sembra che ogni query PubMed sia rappresentata dal suo stesso oggetto. In tal caso, è necessario rendere, ad esempio, la variabile $ searchParameters un membro della classe? Perché non fare semplicemente qualcosa del tipo:

public function setSearchParameters() {
    return array(
        'db'         => 'pubmed',
        'term'       => $this->query,
        'retmode'    => 'xml',
        'retstart'   => '0',
        'retmax'     => '1000',
        'usehistory' => 'y'
    );
}

E poi, per il prossimo metodo nella sequenza:

public function setSearchURL() {
    $baseSearchURL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils /esearch.fcgi?';
    return $baseSearchURL . http_build_query($this->setSearchParameters());

}

Perché farlo? Cerca di pensare a cosa sia realmente una variabile membro: è una rappresentazione dello stato dell'oggetto in questione. Il membro $ query ha senso; rappresenta lo stato di base dell'oggetto PubMedQuery. Funzionando all'indietro dal metodo di livello superiore, getEmailAddresses (), tutto nell'oggetto dipende essenzialmente dal membro $ query. Almeno nel codice che hai fornito, gli altri metodi funzionano semplicemente su questa variabile membro in successione. (Probabilmente avrei impostato la variabile $ baseSearchURL come costante anziché come variabile, ma questo va oltre lo scopo di questa risposta).

Rimuovendo la variabile membro $ searchParameters e strutturando il codice più come mostrato sopra, si elimina anche la necessità del metodo getter, che riduce l'accoppiamento. Se per qualche motivo un altro oggetto ha bisogno della variabile $ searchParameters non membro prodotta dal metodo setSearchParameters, è possibile mantenere pubblico quel metodo. Se sei sicuro che nessun altro oggetto ne avrà bisogno, rendilo privato o protetto. Ancora una volta, non conosco le tue esigenze, ma sospetto che nulla oltre al tuo metodo di alto livello debba essere pubblico. Per ridurre ulteriormente l'accoppiamento, se rendi pubblico solo il tuo metodo di primo livello, puoi definirlo come un metodo di interfaccia. In questo modo, gli oggetti che dipendono dall'oggetto PubMedQuery possono invece dipendere dall'interfaccia.

In genere tendo a provare a ripensare il design di una classe se finisco con più di alcune variabili membro. Se risulta che ho davvero bisogno di un oggetto per tenere traccia di tanti stati, comincio a pensare che forse potrei voler rifattorizzare parte del codice di quell'oggetto in altri oggetti. Un oggetto dovrebbe avere solo una responsabilità. Sono sicuro che i casi esistano, ma personalmente non ho mai dovuto creare un oggetto che fosse necessario tenere traccia di più di quattro o cinque variabili membro al massimo per soddisfare tale responsabilità.

Nel complesso, sei decisamente sulla strada giusta. La suddivisione della responsabilità generale di un oggetto in più metodi che dipendono l'uno dall'altro all'interno di una classe è sicuramente una buona pratica. Quello che ho discusso qui è semplicemente portare le cose al livello successivo.

    
risposta data 23.10.2011 - 05:02
fonte

Leggi altre domande sui tag