Implementazione di interfacce vs utilizzo di una classe base

1

Sto scrivendo un'applicazione in python. La parte su cui sono poco confuso sta fornendo una piccola struttura al mio codice.

Questo è il requisito di base della mia applicazione web.

Ho questi diversi punti finali:

  1. GET / reports / daywise.
  2. GET / reports / bulk_report_between_date_range.
  3. GET / reports / breakdown_by_age.

Per ciascuno di questi endpoint, ho definito un controller (una classe che gestisce il calcolo del risultato)

Il mio attuale design è il seguente: Ho una classe base definita ReportBuilder , e ha alcuni metodi setter come

  1. setDateRange ()
  2. setkeys ()
  3. setQuery ()
  4. Execute ()

Ora, per ciascun controller, eredito dalla classe base precedente e eseguo l'override dei metodi, se necessario.

class ControllerDayWise(ReportBuilder):
    #..........
class ControllerBulkReport(ReportBuilder):
    #..........
class ControllerBreakdownByAge(ReportBuilder):
    #..........

Il problema con la progettazione sopra è che devo usare i metodi setter in un ordine specifico come devo chiamare setQuery() prima di setDates() , poiché la query avrà ovviamente delle date.

Mentre funziona, so che ci deve essere un modo migliore per strutturare la mia applicazione. Così, durante la ricerca, ho trovato l'utilizzo di interfacce in python zope.interface .

L'idea è che creerò un'interfaccia IReportBUilder e che i controllori la implementeranno. Solo con questo, tutti i attributes e methods devono essere ridefiniti in tutti i controller.

Qualche suggerimento sui pro / contro di ciascun metodo che ho considerato sopra? Come dovrei avvicinarmi a questo?

    
posta anekix 21.05.2018 - 09:06
fonte

2 risposte

4

Penso che tu stia rappresentando in modo errato la relazione tra le tue classi. Si sta tentando di definire un controller come un tipo di generatore di report, quando in realtà la responsabilità di un controller (nel contesto di un framework di tipo MVC) consiste nel eseguire il marshalling di una richiesta in altre aree del proprio codebase.

Questo esempio semplificato non evidenzia realmente il problema (il tuo controllore sta restituendo report, potrebbe essere pensato come un generatore di report), ma pensa a tutte le altre cose che il controller deve fare (registrazione, gestione della sicurezza ecc.). Il tuo attuale approccio si interromperà rapidamente se proverai a rappresentare tutte queste attività con una relazione di ereditarietà.

Un modello migliore sarebbe accettare il builder della richiesta come dipendenza dal controller. A seconda del costo del builder del report da creare, è possibile creare ciascun controller con una singola istanza oppure fornire una sorta di factory, in modo da poter creare un nuovo builder del report ogni volta che viene chiamato il metodo del controller.

In questo modo, i metodi del controller possono essere responsabili dell'acquisizione di tutti i parametri necessari per ciascun report e possono quindi chiamare i metodi sul builder del report nell'ordine corretto.

Alcune aree che potresti voler leggere su quest'area sono:

  • "Composizione sull'ereditarietà" ( link )
  • Iniezione delle dipendenze
  • Principio di responsabilità singola

Python non è proprio il mio strong, e il metodo esatto per farlo dipenderà dal framework che stai usando, ma un controller di esempio potrebbe assomigliare a questo:

class ExampleController:
    def __init__(self, report_builder_factory):
        # report builder factory could be either a function or an instance of a class
        self.report_builder_factory = report_builder_factory

    def get_daterange_report(self, start, end):
        report = self.report_builder_factory().set_date_range(start, end).execute()
        return report # Wrap this in whatever your framework provides for successful responses

Questo approccio semplifica anche i test. È possibile testare i controllori fornendo un'implementazione fittizia del generatore di report e testare il generatore di report senza doversi preoccupare dei requisiti del controller

    
risposta data 21.05.2018 - 12:24
fonte
2

Quello che stai cercando è un pattern Step Builder per applicare i metodi in un certo ordine. Comunque direi che vuoi fare tutto ciò che c'è dentro il controller. È possibile avere un produttore di report build che implementa il modello di build step e creare un'istanza della factory in base ai requisiti all'interno del controller. Ulteriori informazioni sul modello di build dei passaggi: link

    
risposta data 21.05.2018 - 17:07
fonte