Gli oggetti di ritorno complessi devono essere avvolti in una classe helper?

3

Nel refactoring del codice ho trovato un metodo helper get_records_from_file che ha una firma di ritorno complessa:

class RecordDefinition:

    def __init__(self):
        self.foo = None
        self.bar = None

def get_records_from_file(file_name) -> Dict[int, List[Dict[str, RecordDefinition]]]:
...

Dopo qualche ispezione capisco che questo tipo di ritorno significa davvero:

Dict[record_group_id, List[Dict[record_type_id, RecordDefinition]]]

In altri progetti (e in altre lingue) ho visto cambiare questa cosa in:

Dict[record_group_id, List[RecordTypeCollection]]

Che porta a:

Dict[record_group_id, RecordCollection]

E finalmente termina in:

RecordGroupCollection

In generale, questo tipo di sostituzione è auspicabile? Più esplicitamente, dovrei cambiare oggetti di ritorno complessi come questo in classi orientate agli oggetti? Vedo qui alcuni vantaggi che consentono alle strutture di essere nominate più esplicitamente. Ma questo aggiunge un sacco di codice sotto forma di classi più piccole.

In python ho l'impressione che questo tipo di creazione di classe sia disapprovato. La mia ipotesi è corretta?

    
posta SyntaxRules 16.04.2018 - 23:25
fonte

2 risposte

7

Penso che PEP 20 possa fornire alcune indicazioni qui.

Explicit is better than implicit.

La creazione di una classe wrapper per questa struttura dati ha il vantaggio di rendere il codice più esplicito attraverso la denominazione della struttura e dei suoi campi componenti.

Questo potrebbe essere supponente, ma penso che quanto segue si applichi anche al tuo esempio:

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Una classe con metodi e campi sarebbe meno "annidata" rispetto alla struttura dei dati grezzi.

Tuttavia ...

[...] practicality beats purity.

Non penso sia sicuro affermare come una regola dura e veloce che dovresti sempre avvolgere strutture annidate. Una classe wrapper potrebbe essere eccessiva se sta avvolgendo una struttura molto semplice (ad es., Forse, se il metodo restituisse solo una tupla di un elenco e un altro tipo di dati). È anche discutibile che se la classe non ha un nome di dominio business migliore di Collection , potrebbe essere troppo astratto per aggiungere valore.

La domanda da porre quando valuti se creare una classe in queste situazioni è, pensi che più sviluppatori troveranno più facile lavorare con la nuova classe o la struttura dati originale?

Nell'esempio che hai fornito, penso che sia molto ragionevole (e secondo me preferibile) creare la nuova classe.

    
risposta data 17.04.2018 - 01:17
fonte
2

Bene, sì, ma nei casi simili al tuo esempio potresti essere meglio con un cursore o un enumeratore perché questo (avvolgendolo tutto in un oggetto complesso) non scala molto bene. Allo stesso modo, se è necessario passare i dati da un file, è possibile restituire un'interfaccia di flusso anziché tutti i dati dal file racchiuso in una struttura. Quest'ultima soluzione richiederebbe potenzialmente un enorme buffer in memoria.

In termini OO questa è una forma di aggregazione sul contenimento. Ci sono trade off, restituendo un flusso aperto trasferire la responsabilità di eliminarlo (chiudendo il file) al ricevitore, il che rende la gestione degli errori più complessa. Quindi dipende da cosa ci si può aspettare in termini di dimensioni dei dati e di come si useranno quei dati (tutto in una volta o frammentario per tutta la durata della sessione). Non esiste una risposta universalmente applicabile.

    
risposta data 17.04.2018 - 07:31
fonte

Leggi altre domande sui tag