Dipendenze di interfaccia o classi astratte

1

Ho una decisione da prendere e mi chiedo quale sarebbe la soluzione migliore. Sto rifattorizzando una vecchia applicazione e intendo davvero entrare nel merito.

Al momento sono disponibili 8 tipi di rapporto e una delle modifiche consente di "salvare" diversi rapporti in diversi modi. I miei due pensieri su di esso erano

  1. Avere una classe astratta con un metodo di salvataggio astratto, quindi ogni tipo di rapporto può definire il proprio modo di fare le cose. Forse hanno altre classi astratte che ereditano da quella, ognuna delle quali implementa un metodo virtuale Save() . Quindi le classi di report possono ereditare da quella con il meccanismo di salvataggio pertinente.

  2. Avere un'interfaccia di report, che ha una firma del metodo come

    void Save(ISaveMechanism saveMechanism);
    

    Quindi disponi di un'interfaccia con un metodo Save() , quindi ogni tipo di rapporto può utilizzare saveMechanism.Save(); e utilizzare solo l'implementazione concreta richiesta.

Una delle due soluzioni potrebbe causare più problemi / svantaggi rispetto alle altre? Al momento questo progetto non ha alcun test unitario associato, ma se avessi tempo, sarebbe opportuno aggiungerne alcuni più tardi.

    
posta James 19.11.2013 - 22:31
fonte

1 risposta

8

Non penso che sia un o / o. Penso che dovresti utilizzare entrambe Interfacce e Classi astratte.

TL; DR

Classi astratte

Pro:

  • Relativamente semplice
  • Puoi fornire funzionalità di base e "hook" che le sottoclassi possono utilizzare.

Contro:

  • Sei "bloccato" con la gerarchia dell'ereditarietà
  • Il codice client conosce la classe base

Interfacce

Pro:

  • Flessibilità quasi illimitata

Contro:

  • Implementazione zero fornita
  • Potrebbe essere più difficile capire i programmatori meno esperti.

Scenario

Immagina di creare una classe astratta oggi. Lo chiameremo BaseReport . BaseReport fornisce un metodo di "salvataggio" vuoto e tutti i tuoi attuali tipi di rapporti si estendono da BaseReport e hanno la loro implementazione di salvataggio.

Per ragioni, vuoi anche visualizzare il testo del rapporto prima di salvarlo, quindi il tuo BaseReport estende un semplice componente View fornito dalla tua lingua di scelta che ti permetterà di mettere alcuni oggetti di testo e un salvataggio pulsante sullo schermo e non molto altro. È davvero leggero, quindi è una buona scelta basata su tutti i report che hai di fronte. Lo chiamerò SimpleContainer .

Ora hai nove mesi di tempo e devi avere un rapporto con più pagine e qualcuno ha chiesto che uno dei report sia visualizzabile in modalità verticale o orizzontale. Nessuno di questi requisiti può essere soddisfatto con una sottoclasse di SimpleContainer.

Tuttavia, hai un sacco di codice client che conosce BaseReport, e ci potrebbe anche essere un posto o due in cui hai eseguito il cast su SimpleContainer (dov'è il danno?). Non solo, il codice è più simile al codice framework personalizzato e hai generato quattro progetti che lo utilizzano. Quindi tutti di quei progetti dovranno passare di nuovo al QA se si fa il refactoring su IReport in modo da poter estendere PagedContainer per il report e RotatableContainer per l'altro. Più che probabile, a questo punto la tua risposta è "scusa, non possiamo farlo." Non perché non puoi davvero farlo, ma perché è troppo rischioso per tutte le altre cose che ti siedono sopra.

Ma negli ultimi 9 mesi, ti sei evoluto come gangbusters perché avevi quel codice base in BaseReport che ti permetteva di strappare un nuovo tipo di rapporto in tempi record, quindi non vuoi buttare il bambino fuori con l'acqua sporca. Invece, rendi il tuo BaseReport implementare IReport e assicurati che il codice client solo si riferisca ad esso come IReport. Quando arriva il requisito per un PagedContainer, crea un BasePagedContainer che implementa IReport e poi crea i tuoi singoli rapporti in cima.

Non c'è davvero uno svantaggio di questo approccio, perché la quantità di lavoro necessaria per creare l'interfaccia e implementarla nelle classi astratte è minuscola rispetto alla quantità di flessibilità e a prova di futuro che ottieni.

E potrei aver cambiato qualche dettaglio per proteggere l'innocente, ma lo scenario è reale, e mi è successo. :)

    
risposta data 20.11.2013 - 00:59
fonte