È una buona idea inserire un gruppo di funzioni statiche che sono correlate l'una con l'altra in termini di ambito all'interno di una classe?

4

La lingua è PHP. Ho diverse funzioni che si riferiscono l'un l'altro (e talvolta si usano l'un l'altro) che ho deciso di accoppiare sotto la stessa classe.

Ecco i miei ragionamenti, tieni presente che sono limitato da ciò che ancora non so in termini di come verrà utilizzato il mio codice:

These functions have no clear need for a class on their own.

These functions I only need as small bits for random events throughout my other codebase.

These functions I see as a "package of methods that relate to a certain scope", e.g functions that deal with file functionalities (write / read / append, etc.)

These functions help me avoid over-Dependency Injecting; while the classes that use these methods cannot work without these methods, as such, they're depdendent on these methods, it makes no sense to DI the class that contains these methods because it over-complicates code that should be simple.

These functions are a core part that should never be touched, they're provided to you "as is". Static methods cannot be overwritten and this is a plus in my case. Under no circumstance do I want developers to meddle with them.

It is more elegant to write use Package; than require_once for every file, using Composer will leave the functions out in the global scope which I don't want.

Ed ecco il mio codice attuale, appena rimosso dalla funzionalità:

class FilesHelpers
{
    public static function saveFileToDisk(){}

    public static function saveExportFile(){}

    public static function getFilePath(){}
}

Come puoi vedere, queste funzioni trattano tutti i file, ma come affermato in precedenza, raramente si toccano e generalmente sono in grado di stare in piedi da soli, senza bisogno di altre funzioni.

Dico semplicemente use FilesHelpers e chiamo il metodo che mi serve.

Voglio che queste funzioni siano prontamente accessibili, ma ho pensato che non è una grande idea dato che non ho davvero bisogno di loro tranne che per i posti in cui ho bisogno di loro, mentre renderle statiche non mi aiuta con questo, in Nella mia mente, un insieme di funzioni statiche che non si interessano a vicenda in una classe sono più "disaccoppiati" rispetto alle funzioni non statiche che richiedono l'istanziazione degli oggetti.

Se dovessi dirlo in altre parole: non voglio che le classi che usano queste funzioni abbiano delle dipendenze perché possono essere facilmente scambiate, se usi la mia classe, usi questi metodi, nessuna discussione, se vuoi fare il processo in un altro modo, va bene, hai l'interfaccia principale su cui puoi scrivere e non hai bisogno di usare le mie funzioni statiche.

È questo l'approccio giusto?

    
posta coolpasta 09.11.2018 - 04:27
fonte

4 risposte

8

Questo è esattamente ciò che gli spazi dei nomi sono per, e PHP li ha ottenuti! Le procedure possono essere indipendenti e non globali purché tu dia loro il proprio spazio dei nomi.

Ora stai usando metodi statici su una classe per emulare il namespacing. Perché non usare solo spazi dei nomi?

    
risposta data 09.11.2018 - 06:54
fonte
2

Cercherò di rispondere alla tua domanda da un punto di vista di PHP. Penso che quello che stai cercando sia definirli in un tratto . Citato direttamente da quel link, l'enfasi è mia.

Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.

A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.

Come altri hanno sottolineato, i metodi statici non hanno effetti collaterali, quindi preferisco non usarli in questo caso.

Inserirli in un tratto ti consente di inserire i metodi dove necessario, con una semplice dichiarazione d'uso (vedi esempio sotto). A seconda di come sono i tuoi spazi dei nomi e dove si trova il tratto rispetto alla tua classe attuale in cui utilizzi la caratteristica, potresti dover includere un'istruzione di utilizzo aggiuntiva al di fuori della classe, come dovresti fare per qualsiasi classe / interfaccia / tratto fuori dallo spazio dei nomi corrente.

Classe in cui utilizzi il tratto:

<?php    
namespace Namespace/For/Your/Class;

use Namespace/For/Your/Trait/FileHandlingTrait;
class YourClass {

    use FileHandlingTrait;

}

Tratto reale:

<?php    
namespace Namespace/For/Your/Trait;

trait FileHandlingTrait {

    public function saveFileToDisk(){}

    public function saveExportFile(){}

    public function getFilePath(){}

}
    
risposta data 09.11.2018 - 10:07
fonte
1

Suggerirei che la prima regola delle funzioni statiche è che devono essere "puri", cioè devono essere deterministici e privi di effetti collaterali. saveFileToDisk è un classico esempio di una funzione che ha effetti collaterali mentre scrive sul disco. Quindi quando si arriva a testare il codice che lo utilizza, è necessario scrivere effettivamente in un percorso di file. Questo collega il tuo codice a quegli effetti collaterali e crea test molto fragili:

  1. Non puoi eseguire due test in parallelo se entrambi cercano di leggere / scrivere nello stesso percorso file,
  2. La directory potrebbe non esistere, quindi la scrittura del file fallirà e il test fallirà,
  3. Potresti non avere permessi su quel file, quindi la scrittura fallisce e il test fallisce,
  4. e così via ...

Quindi per il tuo esempio, disaccoppia le cose dagli effetti collaterali con un'interfaccia:

interface iFilesHelpers
{
    public function saveFileToDisk();
    public function saveExportFile();
    public function getFilePath();
}

e iniettare un'implementazione che acceda al file system in fase di runtime, consentendo a tale comportamento di essere deriso nei test:

class RuntimeFilesHelpers implements iFileHelpers
{
    public function saveFileToDisk() {…}
    public function saveExportFile() {…}
    public function getFilePath() {…}
}
    
risposta data 09.11.2018 - 09:41
fonte
-1

No, non è una grande idea. Hai dei requisiti molto specifici e se questo si adatta alle tue esigenze allora fantastico.

Generalmente, creando una classe chiamata SomethingHelper e inserendo un sacco di metodi statici, non è possibile rendere più gestibile il codice più completo di tutti i codebase.

Le statiche su File Microsoft sono un buon esempio. Sembrano semplificare le cose, fino a quando non provi a fare alcune cose su PCL multipiattaforma in cui non funzionano.

Modifica , maggiori informazioni su Portable Class Lib e System.IO come richiesto

Le librerie di classi portatili sono un modo di scrivere codice .net che verrà eseguito su piattaforme in cui il framework .net completo non è supportato. Ad esempio ios.

Poiché i metodi File.Whatever sono statici e non supportati in PCL, qualsiasi codice scritto che li usi non diventa compilatore PCL. devi passare e riscrivere tutto quel codice se vuoi usarlo. Se avessi iniettato un'interfaccia invece, non avresti quel problema.

Questo è il problema di mantenimento della staticità, anche se pensi che avrai sempre bisogno di una sola versione, c'è sempre qualche caso limite sulla linea che non hai considerato.

    
risposta data 09.11.2018 - 07:08
fonte

Leggi altre domande sui tag