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

34

Recentemente ho iniziato a esaminare lo sviluppo di Android. Questo mi ha riportato al mondo dello sviluppo del software Java. L'ultima volta che ho lavorato con Java, lo ammetto, non ho capito OOP quasi quanto (credo) lo faccio ora.

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

In C # sembrava che l'ereditarietà potesse essere evitata nella maggior parte delle situazioni. Di solito il compito da svolgere può essere realizzato utilizzando classi concrete del .NET framework.

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

Questa sembra essere una differenza troppo grande per ridurla in stile. Qual è il ragionamento dietro a questo? Sento che non scriverò codice Java pulito fino a quando non lo capisco.

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

O metti in un altro modo,

Di cosa tratta la progettazione di questi due linguaggi che (sembra incoraggiare) più o meno l'uso dell'eredità rispetto agli altri?

Se le lingue trattano l'ereditarietà in modo identico e presumendo che la mia osservazione sia valida, significa che questo è legato alla progettazione dei framework / librerie e non delle lingue. Quale sarebbe la motivazione per questo tipo di design?

    
posta MetaFight 29.11.2013 - 19:02
fonte

3 risposte

31

This seems to be too big a difference to just boil down to style. What is the reasoning behind this?

La mia comprensione è che in larga parte è semplicemente una decisione stilistica. Beh, forse non lo stile, ma gli idiomi della lingua / ambiente. Gli sviluppatori di librerie standard Java hanno seguito un set di linee guida di progettazione e gli sviluppatori .NET di un'altra (sebbene avessero la possibilità di vedere come funzionava l'approccio di Java).

Nelle lingue attuali c'è molto poco per incoraggiare o dissuadere l'ereditarietà. Solo due cose mi sembrano rilevanti:

  1. .NET ha introdotto i generici prima della loro vita, prima che fosse implementato troppo codice non generico. L'alternativa è un sacco di ereditarietà per tipo specializzare le cose.

  2. Una modifica più ampia riguardava i delegati supportati da .NET. In Java sei bloccato con l'ereditarietà (anonima) per fornire la più basilare delle funzionalità variabili. Ciò comporta una differenza relativamente grande nel modo in cui il codice è progettato per trarre vantaggio dai delegati o per evitare le strutture di ereditarietà necessarie per farlo in Java.

risposta data 29.11.2013 - 21:54
fonte
6

Sono lingue molto diverse, in particolare in quest'area. 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, dal momento che utilizziamo un'interfaccia utente per il nostro esempio, la chiameremo classe CleverPanel. La nostra istanza di CleverPanel vorrà conoscere le cose che accadono nella sua istanza di UIControl per vari motivi. Come si fa?

In C #, l'approccio di base è controllare vari eventi, impostando i metodi che verranno eseguiti quando viene attivato ogni evento interessante. In Java, a cui mancano gli eventi, la solita soluzione è passare un oggetto con vari metodi di gestione "evento" 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 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 per ignorare i metodi di cui abbiamo bisogno per far sì che il programma funzioni correttamente. Quindi alla fine abbiamo bisogno di un'interfaccia e che utilizzi l'ereditarietà in Java per corrispondere a 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 ereditarietà in Java rispetto a C #.

Ora, perché Java funziona in questo modo? Flessibilità. L'oggetto passato a whenSomethingHappens 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. O l'UIControl potrebbe consegnarlo a uno dei suoi componenti.

Inoltre, al posto di un adattatore potrebbe esserci un'implementazione DoSomething da qualche parte che contiene migliaia di linee di codice. Potremmo creare una nuova istanza di che e passarla. Potremmo aver bisogno di sovrascrivere un metodo. Un trucco comune in Java è di avere una classe grande 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, il che tende a spingere i programmatori a fare di più - sia perché lo seguono come un esempio che semplicemente per usarlo. Penso che il design di base del linguaggio sia alla base del framework di Sun e dietro il programmatore Java che usa le tecniche quando non usa 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 piccole modifiche a una classe molto grande ed esistente. (E la classe esistente può essere di primo livello nel proprio file o nidificata in una classe di primo livello o definita solo all'interno di un singolo blocco di codice). La nuova istanza di classe può avere accesso completo 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 lo ha creato.

(Come nota a parte, si noti che un grande uso dell'eredità qui - come in altri posti in Java - è semplicemente a scopi DRY. Consente a diverse classi di riutilizzare lo stesso codice. Nota anche la facilità di ereditarietà in Java che lo incoraggia.)

Ancora una volta, questa non è una discussione completa; Sto solo grattando la superficie qui. Ma sì, c'è una sorprendente differenza nel modo in cui viene utilizzata l'ereditarietà tra Java e C #. Sono, sotto questo aspetto, linguaggi molto diversi. Non è la tua immaginazione.

    
risposta data 30.11.2013 - 05:45
fonte
-2

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

Spero di aver aiutato!

    
risposta data 29.11.2013 - 20:41
fonte

Leggi altre domande sui tag