Utilizzo di una classe one-shot per memorizzare variabili non del tutto globali

4

A volte mi trovo a scrivere classi (in Python, nel mio caso) che sono usate in questo modo:

MyClass(some_args).go()

In altre parole, c'è un solo metodo nella classe che qualsiasi codice esterno chiamerebbe e verrà sempre chiamato solo una volta. Potrebbe esserci un valore di ritorno da go() , ma spesso non c'è, e quando non c'è, potrei anche chiamare go dal __init__ della classe.

Quindi perché preoccuparsi della classe, invece di scrivere go() come funzione autonoma? Perché ciò che accade all'interno di go è complicato. Potrebbero esserci diversi livelli di chiamate di funzioni nidificate e alcune informazioni necessarie in punti diversi. Se provo a scrivere tutto questo senza una classe, finisco con molte delle funzioni che restituiscono più valori. A volte anche le liste degli argomenti diventano lunghe a disagio. Se avvolgo tutto all'interno di MyClass , allora posso inserire tutte queste informazioni nelle variabili membro dell'istanza MyClass . Queste diventano variabili non del tutto globali, e generalmente sono roba che sembra aver senso memorizzare in una classe.

Questa pratica ha un nome? È un modello o un anti-modello? E se quest'ultimo, come dovrei strutturare il mio codice, invece?

    
posta kuzzooroo 13.06.2015 - 20:11
fonte

4 risposte

1

Questo è un naturale progresso di incapsulamento, astrazione e organizzazione generale del codice. Man mano che estrai pezzi di codice da una funzione nelle loro funzioni separate, puoi notare che condividono molti stati che richiedono il passaggio di numerosi parametri. Promuovere questo stato nei campi di una classe - e dette funzioni ai metodi della classe - aiuta a ridurre il disordine e migliorare la leggibilità.

Si noti che in linguaggio come Python, dove sono consentite funzioni standalone, è possibile nascondere l'esistenza della classe dietro una funzione che istanzia l'oggetto e chiama il suo metodo go . In questo modo, la classe diventa un dettaglio di implementazione e la tua API rimane la stessa, anche se ad es. la logica diventa abbastanza complicata da giustificare un intero sotto-pacchetto.

    
risposta data 15.06.2015 - 00:00
fonte
4

Come ha detto Ixrec - metti l'implementazione in un altro file. Ma dal momento che hai bisogno di uno stato che non vuoi rendere globale - inserisci quello stato in una classe!

OK, è venuto fuori un po 'di confusione. Quello che intendo è di mantenere la classe, ma nasconderla all'utente. L'utente vedrà solo una funzione globale che crea internamente la classe e chiama il suo metodo go . In realtà, abbandonare go . Poiché tutto ciò che fa è chiamare altre funzioni, probabilmente dovresti farlo da quella funzione esterna.

Quindi, invece di

class MyClass:
    def __init__(self):
        self.x = 1
        self.y = 2

    def op1(self):
        self.x += self.y

    def op2(self):
        self.y += self.x

    def go(self):
        self.op1()
        self.op2()
        return self.x * self.y

Scrivi questo:

class __MyClass:
    def __init__(self):
        self.x = 1
        self.y = 2

    def op1(self):
        self.x += self.y

    def op2(self):
        self.y += self.x

    def calc_result(self):
        return self.x * self.y

def my_function():
    my_object = __MyClass()
    my_object.op1()
    my_object.op2()
    return my_object.calc_result()

In questo modo, hai ancora una classe che contiene tutti i dati, ma l'utente vede una singola funzione.

    
risposta data 14.06.2015 - 12:28
fonte
3

Non penso che questa pratica abbia un nome speciale, la definirei "incapsulamento", "creare un'astrazione utilizzando una classe", "design di classe" o semplicemente "programmazione OO". E sicuramente non è un anti-pattern.

    
risposta data 14.06.2015 - 09:25
fonte
2

Solitamente lunghi elenchi di argomenti e più valori di ritorno possono essere generalmente risolti raggruppando valori in tipi di dati strutturati o incapsulandoli in classi. Se non ci sono raggruppamenti chiari, nasconderlo spostandoli nello stato oggetto con altri valori non correlati è solo dannoso.

I metodi (anche i metodi intesi per essere privati) dovrebbero lasciare gli oggetti in uno stato consistente al loro ritorno. Ciò diventa più difficile da raggiungere quando lo stato dell'oggetto diventa più complesso. Spesso vuol dire prendere in considerazione del codice in funzioni esterne / statiche in modo da avere: 1) un metodo che trasferisce l'oggetto da uno stato valido a un altro, che viene eseguito da 2) funzioni che implementano procedure ben definite, che possono essere superate un sottoinsieme di valori dallo stato dell'oggetto, ma è testabile separatamente .

Infine, una funzione dovrebbe essere esposta come una funzione. Ciò significa che i client devono chiamare my_function(some_args) e non MyClass(some_args).go() . Se my_function è implementato come quest'ultimo, stai almeno isolando il codice client dalle sue ambiguità.

    
risposta data 14.06.2015 - 20:31
fonte

Leggi altre domande sui tag