Lo sviluppo di Java comporta in genere più sottoclassi di C # /. NET?


34

Di recente ho iniziato a guardare allo sviluppo di Android. Questo mi ha riportato nel mondo dello sviluppo del software Java. L'ultima volta che ho lavorato con Java, lo ammetto, non ho capito OOP quasi quanto (penso) lo faccio ora.

Avendo usato principalmente C # nella mia carriera, noto una differenza sorprendente nel modo in cui l'ereditarietà viene utilizzata Java e C #.

In C # sembrava che l'ereditarietà potesse essere evitata nella maggior parte delle situazioni. Il compito a portata di mano di solito può essere realizzato utilizzando classi concrete del framework .NET .

In Java, da quello che sto raccogliendo da esempi di codice, sembra che il framework Java fornisca molte interfacce o classi astratte che dovrebbero essere implementate / estese dallo sviluppatore.

Questa sembra essere una differenza troppo grande per ridursi allo stile. Qual è il ragionamento alla base di questo? Sento che non scriverò codice Java pulito fino a quando non lo capirò.

Inoltre, questo è limitato solo all'SDK di Android o è un approccio Java a OOP?

O in un altro modo,

Cosa c'è nella progettazione di questi due linguaggi che (sembra incoraggiare) un uso più o meno ereditario dell'altro?

Se le lingue trattano l'eredità in modo identico e supponendo che la mia osservazione sia valida, significa che ciò è correlato al design dei framework / librerie e non alle lingue. Quale sarebbe la motivazione per questo tipo di design?


1
È vero. Java ha troppe interfacce. Mi piacerebbe sapere perché questo comportamento degli sviluppatori è comune per una lingua specifica. Vedo che ciò accade più spesso nei progetti Java rispetto a qualsiasi altro. Deve esserci una ragione per questo e non solo un'opinione.
Reactgular,

1
@MathewFoscarini è solo la tua opinione . Ai progetti Java a cui ho partecipato, gli sviluppatori erano propensi a evitare l'eredità come una piaga. Nulla di autorevole qui, solo la mia opinione . Vuoi sondaggio ?
moscerino del

2
Quasi, non hai mai bisogno di derivare una classe da un'altra in Java. Al contrario, è possibile implementare interfacce per ottenere il polimorfismo e implementare oggetti composti e eseguire il proxy delle chiamate del metodo per ottenere funzionalità shaired.
DW

1
@ThinkingMedia In generale, Java è invasa da zeloti / puristi OSS. I principi accademici sono la preoccupazione principale. Gli sviluppatori .Net sono pragmatici che si preoccupano di portare a termine il lavoro. Stimano il codice di lavoro più del codice più pulito.
Andy,

Risposte:


31

Questa sembra essere una differenza troppo grande per ridursi allo stile. Qual è il ragionamento alla base di questo?

La mia comprensione è che in gran parte è semplicemente una decisione stilistica. Beh, forse non lo stile, ma gli idiomi del linguaggio / ambiente. Gli sviluppatori di librerie standard Java hanno seguito una serie di linee guida di progettazione e gli sviluppatori .NET un'altra (anche se avevano la capacità di vedere come funzionava l'approccio Java).

C'è molto poco nelle lingue attuali per incoraggiare o dissuadere l'eredità. Solo due cose mi sembrano rilevanti:

  1. .NET ha introdotto i generici all'inizio della loro vita, prima che fosse implementato troppo codice non generico. L'alternativa è molta eredità per scrivere cose specializzate.

  2. Un cambiamento più grande è stato che .NET ha supportato i delegati. In Java sei bloccato con l'ereditarietà (anonima) per fornire le funzionalità variabili di base. Ciò porta a una differenza relativamente grande nel modo in cui il codice è progettato per sfruttare i delegati o per evitare le strutture di ereditarietà scomode necessarie per farlo in Java.


3
Penso che questa risposta offra una spiegazione molto plausibile. Soprattutto il punto sull'eredità anonima al posto dei delegati. L'ho osservato molto. Grazie.
MetaFight,

3
Non dimenticare i tipi anonimi e gli alberi di sintassi / espressioni lambda introdotti in .NET 3.5. E ovviamente optare per la tipizzazione dinamica in .NET 4. Ora è quasi senza dubbio un linguaggio a paradigma misto, non strettamente orientato agli oggetti.
Aaronaught,

sì, nella mia esperienza avendo usato entrambi (anche su progetti misti in cui le stesse persone usano entrambe le lingue) le persone tendono a preferire l'uso di un numero maggiore di classi più piccole quando codificano Java, un numero più piccolo di classi più grandi (tendendo verso le classi divine) quando usando C #. Avendo prototipato deliberatamente la stessa cosa usando lo stesso stile in entrambi, finisci con un numero simile di classi (usando classi parziali, probabilmente finiresti con più file di codice anche quando usi C #).
jwenting

6

Queste sono lingue molto diverse, in particolare in questo settore. Diciamo che hai una lezione. In questo caso, lo renderemo un controllo utente, qualcosa come una casella di testo. Chiamalo UIControl. Ora vogliamo metterlo in un'altra classe. In questo caso, poiché utilizziamo un'interfaccia utente per il nostro esempio, la chiameremo classe CleverPanel. La nostra istanza CleverPanel vorrà conoscere le cose che accadono alla sua istanza UIControl per vari motivi. Come fare questo?

In C #, l'approccio di base consiste nel verificare la presenza di vari eventi, impostando metodi che verranno eseguiti quando viene attivato ogni evento interessante. In Java, che manca di eventi, la solita soluzione è passare un oggetto con vari metodi di gestione di "eventi" a un metodo UIControl:

boolean  stillNeedIt =  ... ;
uiControl.whenSomethingHappens( new DoSomething()  {
    public void resized( Rectangle r )  { ... }
    public boolean canICloseNow()  { return !stillNeedIt; }
    public void closed()  { ... }
    ...
} );

Finora, la differenza tra C # e Java non è profonda. Tuttavia, abbiamo l'interfaccia DoSomething che non è necessaria in C #. Inoltre, questa interfaccia potrebbe includere molti metodi che non sono necessari per la maggior parte del tempo. In C #, non gestiamo quell'evento. In Java, creiamo una classe che fornisce un'implementazione nulla per tutti i metodi di interfaccia, DoSomethingAdapter. Ora sostituiamo DoSomething con DoSomethingAdapter e non abbiamo bisogno di scrivere alcun metodo per una compilazione pulita. Finiamo solo per ignorare i metodi di cui abbiamo bisogno per far funzionare correttamente il programma. Quindi abbiamo bisogno di un'interfaccia e di usare l'ereditarietà in Java per abbinare ciò che abbiamo fatto con gli eventi in C #.

Questo è un esempio, non una discussione completa, ma fornisce le basi del perché c'è così tanta eredità in Java rispetto a C #.

Ora, perché Java funziona in questo modo? Flessibilità. L'oggetto è passato a quando SomethingHappens avrebbe potuto essere passato a CleverPanel da qualche altra parte completamente. Potrebbe essere qualcosa che diverse istanze di CleverPanel dovrebbero passare ai loro oggetti simili a UIControl per aiutare un oggetto CleverWindow da qualche parte. Oppure UIControl potrebbe consegnarlo a uno dei suoi componenti.

Inoltre, invece di un adattatore potrebbe esserci un'implementazione DoSomething da qualche parte che ha migliaia di righe di codice dietro di esso. Potremmo creare una nuova istanza di quello e passarlo. Potrebbe essere necessario sostituire un metodo. Un trucco comune in Java è avere una grande classe con un metodo come:

public class BigClass implements DoSomething  {
    ...many long methods...
    protected int getDiameter()  { return 5; }
}

Quindi in CleverlPanel:

uiControl.whenSomethingHappens( new BigClass()  {
    @Override
    public int getDiameter()  { return UIPanel.currentDiameter; }
} );

La piattaforma Java open source fa molto di questo, che tende a spingere i programmatori a fare di più, sia perché la seguono come esempio sia semplicemente per usarla. Penso che il design di base del linguaggio sia alla base della progettazione del framework Sun e dei programmatori Java che usano le tecniche quando non usano il framework.

È davvero facile creare una classe al volo in Java. La classe, anonima o denominata, deve essere referenziata solo in un piccolo blocco di codice sepolto in profondità in un metodo. Può essere creato completamente nuovo o con lievi modifiche a una classe esistente molto ampia. (E la classe esistente può essere di livello superiore nel proprio file o nidificata in una classe di livello superiore o definita solo all'interno di un singolo blocco di codice). La nuova istanza della classe può avere pieno accesso a tutti i dati dell'oggetto di creazione. E la nuova istanza può essere passata e utilizzata in tutto il programma, rappresentando l'oggetto che l'ha creata.

(A parte, nota che un grande uso dell'eredità qui - come in altri luoghi in Java - è semplicemente per scopi SECCHI. Permette a classi diverse di riutilizzare lo stesso codice. Nota anche la facilità di eredità in Java che lo incoraggia. )

Ancora una volta, questa non è una discussione esauriente; Sto solo grattando la superficie qui. Sì, c'è una differenza sorprendente nel modo in cui l'ereditarietà viene utilizzata tra Java e C #. Sono, a questo proposito, lingue molto diverse. Non è la tua immaginazione.


Nota: è possibile evitare di fornire metodi che non fanno nulla estendendo una classe astratta piena di implementazioni vuote. In questo modo puoi scavalcare selettivamente i metodi che fanno qualcosa. Sebbene non sia così brutto, significa un altro livello di eredità.
Peter Lawrey,

-2

Non c'è assolutamente alcuna differenza nel modo in cui l'ereditarietà viene gestita tra Java e C #. Quando si utilizzerà effettivamente l'ereditarietà o la composizione è sicuramente una decisione di progettazione e in nessun modo qualcosa che Java o C # incoraggia o scoraggia. Consiglio di leggere questo articolo .

Spero di averti aiutato!


5
Stai parlando delle lingue stesse, ma penso che la domanda riguardi anche le librerie e l'uso comune.
svick,

3
Ma ci sono stranezze nel resto del linguaggio che incoraggiano l'eredità extra in Java; vedi la risposta di
RalphChapin
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.