OOP: Quali sono alcune delle situazioni in cui il design basato su classi è migliore di quello basato su interfaccia?


9

Stavo leggendo il sito Web di JDOM .

Perché l'API JDOM è definita in termini di classi concrete anziché di interfacce?

Jason Hunter riassume gli argomenti contro un'API basata su interfaccia per JDOM:

Con le interfacce tutto diventa una fabbrica, gli elementi devono essere "importati" in nuovi documenti anziché semplicemente aggiunti, funzionalità come la serializzazione a lungo termine non possono essere garantite e l'elenco continua.

Abbiamo iniziato con le interfacce in realtà. Durante la nostra recensione pre-release ad alcuni colleghi abbiamo ricevuto il feedback che dovremmo provare con lezioni concrete. Lo abbiamo fatto e il design è stato molto meglio.

Sono un designer principiante. Tutti i consigli di cui ho sentito finora sono sconsigliati di utilizzare la progettazione con lezioni concrete.

Può essere che le classi concrete siano appropriate in determinati luoghi. Ci sono problemi di classe comuni per i quali l'utilizzo di classi concrete nel design va bene?



Puoi anche dare un'occhiata alla serie "Limita le tue astrazioni": ayende.com/blog/153889/…
henginy

"L'abbiamo fatto e il design è stato molto meglio." - com'è andata meglio?
CodeART

Risposte:


5
  • L'ereditarietà crea dipendenze dall'implementazione , che potrebbe essere un grosso problema per quanto riguarda la manutenibilità. Il corollario di ciò è che puoi usare in modo sicuro ereditarietà e classi concrete quando hai a che fare con un oggetto di trasferimento dati , che per definizione non contiene quasi nessuna implementazione. È inoltre possibile utilizzare l'ereditarietà di classi concrete quando si desidera questa dipendenza. In questa situazione potresti voler utilizzare una classe astratta contenente i metodi comuni (di solito funzioni di utilità) nella parte superiore della gerarchia.
  • Quando si utilizza una gerarchia di classi concrete, non dimenticare di applicare il Principio di sostituzione di Liskov .
  • Non vi è alcun problema con l'utilizzo di classi concrete per i client (ovvero classi che utilizzano, non classi utilizzate).
  • IMHO puoi usare classi concrete fino a quando non ci sono cose da cambiare. Il principio aperto / chiuso ti direbbe di usare le interfacce per evitare l'accoppiamento, ma per quanto riguarda il principio "Non hai bisogno" potresti prendere in considerazione l'uso di classi concrete fino al momento in cui devi cambiare qualcosa nell'implementazione. Il problema è che dovresti cambiare ogni cliente delle tue classi la prima volta che qualcosa cambia da qualche parte. Mentre hai solo uno strumento possibile per fare qualcosa, puoi usare classi concrete IMO.

[EDIT] Il sito Web di JDOM prende java.io.File come esempio, ma questa è sicuramente una progettazione basata su interfaccia in quanto si può manipolare un'istanza java.io.File come se fosse solo una serializzabile. In questa situazione solo i "creatori" conoscono la classe concreta


Esistono due definizioni contrastanti di "oggetto valore" fluttuanti. Il tuo sembra essere il meno comune, noto anche come "oggetto di trasferimento dati".
Michael Borgwardt,

@MichaelBorgwardt Thx per averlo sottolineato perché non intendevo solo "oggetto di trasferimento dati": modifico la mia risposta
Matthias Jouan,

1
LSP è importante per qualsiasi relazione di sottotipizzazione, implementazione dell'interfaccia e ereditarietà.

2

Dal sito JDOM:

Jason (Hunter) ha fondato il progetto JDOM all'inizio del 2000 insieme a Brett McLaughlin

Cioè, all'epoca in cui veniva introdotto Java 1.3. Non c'era nulla in termini di maturità quando si trattava dello sviluppo di Java: gli sviluppatori più esperti avevano al massimo 4 anni di utilizzo di Java. Non c'erano contenitori IoC ampiamente utilizzati, né Hibernate. Apache Struts stava appena iniziando.

Il che è tutto per dire che Jason e Brett avevano torto. Molte persone non l'hanno ancora capito. Se avevano sfondi C ++, beh, non avevi bisogno di interfacce in C ++ (beh, erano lì in C ++, ma non ne avevi davvero bisogno, giusto?), Perché diamine li usi in Java? Bene, ci sono molte buone ragioni, a cui altri possono indirizzarti.

Sicuramente si sbagliavano

tutto ciò che può essere fatto con le interfacce può essere fatto con la sottoclasse

Java non consente l'ereditarietà multipla di classi, ma consente l'implementazione di più interfacce. Questo può fare davvero la differenza.


2

Ricorda, in primo luogo, che nello sviluppo software esistono diversi modi per risolvere un problema e se alcuni sviluppatori utilizzano una tecnica diversa dalla tua, ciò non significa che sia sbagliato.

Uno di questi casi è "interfacce" contro (base) "classi". Ci sono situazioni in cui lo stesso obiettivo può essere raggiunto con entrambe le tecniche.

Per rendere le cose, più complicate, ci sono diversi usi delle interfacce, solo per citare:

  • uno è progettare un "contratto" o una "specifica" senza "implementazione"
  • altro per aggiungere funzionalità a una classe o gerarchia di classi esistente
  • complementare al precedente, per consentire l'accesso condiviso tra diversi oggetti, tecnologie, esempio: Enterprise Beans, CORBA, COM, WebServices
  • emulare ereditarietà multipla

La tua domanda si applica al primo punto.

Quando si desidera sviluppare una gerarchia di classi, non solo una singola classe e diverse classi intendono condividere alcune funzionalità specifiche, è possibile iniziare con una classe base, anche se può essere eseguita con un'interfaccia.

E lascia le interfacce per gli altri scenari.

Un buon esempio sono le librerie di widget (controlli).

Suggerisco di dare un'occhiata ad altri linguaggi di programmazione come usano interfacce e classi come: PHP, Delphi (Object Pascal), C #.

Saluti.


0

In genere si desidera un'interfaccia per tutto ciò che viene passato come parametro o restituito, essenzialmente in modo da poter separare la classe dalle sue dipendenze.

Quindi, se stiamo cercando una classe, non passiamo mai in rassegna normalmente le eccezioni che mi vengono in mente. Non sono uno sviluppatore Java, ma certamente in altre lingue simili non credo di aver visto interfacce definite per le eccezioni.


0

Le regole di progettazione dell'API sono davvero specifiche. Non sono sicuro che dovresti concludere qualcosa da quelle FAQ in termini di come progettare il tuo codice quotidiano.

Per il tuo codice normale, è ancora vero che utilizzerai l'interfaccia o l'ereditarietà astratta delle classi molto più spesso dell'ereditarietà vaniglia IMO.

Per comprendere bene quella regola, devi posizionarti non dal punto di vista di una classe derivata rispetto alla sua superclasse, ma dal punto di vista di un oggetto che ha una dipendenza da un altro oggetto. È quasi sempre meglio dipendere da un'astrazione piuttosto che da un'implementazione concreta perché consente di accettare un'intera serie di classi diverse come dipendenze, basandosi sul loro contratto e non sui dettagli dell'implementazione.

Il primo utilizzo è spesso nei test unitari: se vuoi davvero testare l' unità della tua classe in completo isolamento, lo fai contro false implementazioni delle tue dipendenze che sono diverse dalle implementazioni reali che verranno utilizzate nella produzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.