Modifica di una classe esistente: dovrei estenderla a una nuova classe?

2

Sto lavorando con una libreria (da una fonte online, non creata in-house) che fornisce un'interfaccia e un'implementazione di essa:

interface FooInterface {
   // ...
}

class Foo implements FooInterface {
  // ...
}

Non sono soddisfatto dell'implementazione predefinita, Foo , quindi posso sempre scrivere qualcosa del tipo:

class MyFoo implements FooInterface {
  // ...
}

Tuttavia, le modifiche che voglio sono molto piccole; e infatti, se qualche nuovo comportamento / caratteristica arriva in una versione aggiornata della libreria, questo è desiderato a meno che non ci sia una buona ragione per non farlo. A questo punto, ho due scelte:

  • Duplica l'interezza di Foo in MyFoo ad eccezione delle parti modificate e tienilo aggiornato di volta in volta con le modifiche nella libreria.
  • Eredita Foo in MyFoo e apporta modifiche minime in MyFoo .

Quale delle due pratiche precedenti sarebbe incoraggiata dal punto di vista dell'ingegneria del software?

    
posta user2064000 15.08.2016 - 21:37
fonte

2 risposte

4

Se Foo documenta i modi in cui può essere esteso, e puoi ottenere ciò che desideri estendendo Foo , allora questa è la strada da percorrere. Tuttavia è possibile che Foo non sia stato pensato per essere ereditato e l'autore semplicemente trascurato per rendere la classe sealed / final . In questo caso, non dovrebbe ereditare da Foo , perché la sottoclasse potrebbe interrompersi se Foo è refactored in una versione successiva della libreria.

Ad esempio, Foo.bar può essere implementato in termini di Foo.baz ora, ma questo è solo un dettaglio di implementazione. Hai codificato la tua sottoclasse sotto questa ipotesi. Nella prossima versione, bar non chiama più baz e le sottoclassi si interrompono. Potrebbe anche accadere il contrario bar non ha chiamato baz e ora lo fa all'improvviso. Questo è noto come problema di classe base fragile.

C'è una terza opzione che non hai menzionato, che sta usando la composizione: la tua implementazione di FooInterface contiene un riferimento a un'istanza di Foo e la usa per portare a termine il lavoro. Se Foo non è inteso per essere esteso, questa è la strada che consiglierei se possibile.

Se anche non è possibile prendere in considerazione di contattare l'autore della biblioteca e chiedere se è possibile implementare la funzione necessaria (o implementarla tu stesso e inviare loro una richiesta di patch / pull). In questo modo diventa parte della libreria e non devi preoccuparti della tua implementazione diversa dalle versioni future.

    
risposta data 15.08.2016 - 22:10
fonte
1

Dipende da quanto del codice vuoi cambiare. Se non sei soddisfatto di quasi tutte le implementazioni del metodo, dovresti semplicemente scrivere la tua implementazione dell'intera classe.

  • Ma è meglio ereditare MyFoo da Foo , se è una piccola modifica. Sarai in grado di tenere traccia delle modifiche che dovevi apportare. Inoltre, non si romperà alcun modello di progettazione che il codice potrebbe utilizzare tramite l'interfaccia.
  • Non è una buona idea duplicare l'intero Foo in MyFoo . In questo modo, ogni volta che la classe Foo modifica le implementazioni di un metodo o ne aggiunge di nuove, dovrai apportare modifiche alla tua classe MyFoo per renderle disponibili per il tuo codice. È sempre meglio riutilizzare il codice facendo riferimento ad esso piuttosto che duplicarlo.
risposta data 15.08.2016 - 22:01
fonte

Leggi altre domande sui tag