2011-01-10 9 views
16

Mi chiedevo perché Java sia stato progettato senza la direttiva friend disponibile in C++ per consentire un controllo più preciso su quali metodi e variabili di istanza sono disponibili al di fuori del pacchetto in cui è stata definita una classe.Perché la direttiva friend manca in Java?

Non vedo alcuna ragione pratica né alcun inconveniente particolare, sembra solo un problema di progettazione, ma qualcosa che non creerebbe alcun problema se aggiunto al linguaggio.

risposta

9

Ecco alcuni motivi al largo della parte superiore della mia testa:

  • amico non è necessaria. È conveniente, ma non è necessario
  • l'amico supporta un cattivo design. Se una classe richiede l'accesso ad un amico ad un'altra, lo stai facendo male. (vedi sopra, conveniente, non richiesto).
  • incapsulamento di interruzioni di amici. Fondamentalmente, tutti i miei privati ​​appartengono a me, e quel ragazzo laggiù (il mio amico).
+3

+1 per l'incapsulamento :) – fresskoma

+20

-1 per l'incapsulamento. Questo è un malinteso comune. È semplicemente sbagliato. Anche se è vero che 'friend' * può * essere utilizzato per interrompere l'incapsulamento, così le altre funzionalità possono essere utilizzate in modo improprio. Usato correttamente, 'friend' * migliora l'incapsulamento * perché abilita un controllo di accesso più fine:' friend' sostituisce l'uso di 'public', non di' private'. [Spiegazione tecnica alle FAQ C++] (http://www.parashift.com/c++-faq-lite/friends.html#faq-14.2) (Detto questo, sono completamente soddisfatto della visibilità del pacchetto, ma rivendico che 'amico 'L'incapsulamento delle interruzioni è ancora sbagliato.) –

+1

@KonradRudolph Assolutamente d'accordo. Le classi di amici sono essenziali per la separazione delle preoccupazioni. Ad esempio, ho una classe 'Serializer' che dovrebbe essere autorizzata a scrivere nei campi di un'istanza, quindi gli do l'accesso come amico. Altre classi, non possono scrivere specificamente nei campi e devono passare attraverso l'interfaccia che fornisco. L'unico modo per farlo in Java è mettere tutto nello stesso pacchetto. – crush

10

In generale penso che sia stato a causa della complessità cognitiva aggiunto e basso numero di casi in cui si crea un miglioramento.

Direi che il numero estremamente elevato di linee di Java in produzione in questo momento può attestare che la parola chiave friend non è davvero una grande perdita :).

Vedere la risposta di @ dwb per alcuni motivi più specifici.

+3

l'enorme numero di linee di Java in produzione in questo momento può attestare che qualsiasi scelta di progettazione casuale in java è devine. – irreputable

+0

@irreputable Bello ritorno. Comunque stavo scherzando :) –

+0

'friend' esiste sotto forma di visibilità del pacchetto. Non è così flessibile in Java. – crush

2

Perché non pensare semplicemente che Java richiede che le classi di amici siano co-locate? La visibilità privata del pacchetto consente a tutti gli utenti dello stesso pacchetto di accedere a tali membri. Quindi non sei limitato solo agli amici dichiarati esplicitamente, ma permetti a qualsiasi amico (esistente o futuro) di modificare alcuni membri specificamente progettati per questo scopo (ma non i tuoi contenuti privati). Sei ancora in grado di affidarti completamente all'incapsulamento.

+2

Il problema qui è che qualsiasi classe può richiedere di essere membro di qualsiasi pacchetto. Questo sarebbe l'equivalente di me che dico a una guardia di sicurezza che sono tuo amico e la guardia di sicurezza che mi fa cercare nella tua stanza. – Powerlord

+0

Questo non è del tutto vero (non è possibile dichiarare una classe come appartenente ad un pacchetto java. *, Per esempio) e inoltre, se qualcuno ha davvero bisogno di questo tipo di hack (mettendo una classe nel org.apache.commons.logging solo per vedere membri del pacchetto-privato), potevano benissimo usare reflection e setVisible (true). Ma non sto parlando di hack. L'API standard Java fa un uso intensivo di membri privati ​​del pacchetto. –

+2

@R. Bemrose: il meccanismo di visibilità privato/protetto/pubblico/pacchetto non è destinato ad essere una funzionalità di sicurezza. È una funzione di programmazione progettata per aiutare l'incapsulamento. – JeremyP

2

solo per aggiungere alle altre risposte:

C'è il default visibilità pacchetto in Java. Quindi, tu potresti chiamare tutte le classi nello stesso pacchetto confinante. In questo caso hai il controllo esplicito di ciò che mostri ai vicini: solo membri con visibilità del pacchetto.

Quindi, non è proprio un amico ma può essere simile. E sì, anche questo porta a un cattivo design ...

4

Oltre alla visibilità del pacchetto di cui sopra, Java offre anche classi interne e anonime che non sono solo amici di default, ma anche automaticamente hanno un riferimento alla classe contenente. Dal momento che la creazione di tali classi helper è probabilmente l'unico modo ragionevole di utilizzare friend in C++, Java non ne ha bisogno poiché ha un altro meccanismo per questo. Gli iteratori sono un ottimo esempio di ciò.

+0

Interno ma non parziale. – Vozzie

+0

@Vozzie, vero, ma cosa c'entra questo con 'amico'? –

2

A mio parere un qualche tipo di funzione amico (non necessariamente molto simile al C++ s ') sarebbe molto utile in alcune situazioni in Java. Attualmente disponiamo di pacchetti di accesso privato/predefinito per consentire la collaborazione tra classi strettamente accoppiate nello stesso pacchetto (String e StringBuffer per esempio), ma questo apre l'interfaccia di implementazione privata fino all'intero pacchetto. Tra un pacchetto e l'altro abbiamo degli hack di cattiva riflessione che causano un'intera serie di problemi.

C'è un po 'di ulteriore complicazione in questo in Java.C++ ignora le restrizioni di accesso mentre risolve gli overload di funzioni (e simili) - se un programma compila #define private public non dovrebbe fare nulla. Java (principalmente) scarta membri non accessibili. Se l'amicizia deve essere presa in considerazione, allora la risoluzione è più complicata e meno ovvia.

6

Solo un programmatore molto ingenuo e inesperto difenderebbe gli amici. Ovviamente può essere utilizzato in modo improprio, ma lo sono anche i dati pubblici, tuttavia questa funzionalità viene fornita.

Contrariamente all'opinione popolare, qui ci sono molti casi, in particolare per le capacità di infrastruttura, dove l'accesso degli amici porta a un design MIGLIORE, non a un design peggiore. L'incapsulamento viene spesso violato quando un metodo è FORZATO per essere reso pubblico quando in realtà non dovrebbe essere, ma non ci resta altra scelta perché Java non supporta gli amici.

+1

Vorrei poter revocare questa risposta 100 volte. Questa ideologia "amico è cattivo" è pericolosa. – crush

+0

Suggerirei che solo un programmatore ingenuo e inesperto pensa di dover far giocare i propri amici con tutti i loro amici. Rompe l'incapsulamento e non provoca distruzione, quando sono disponibili altri approcci più semplici. –

2

completamente d'accordo con l'affermazione di Spaceghost in his answer

Contrariamente all'opinione popolare, qui molti casi, in particolare per la capacità di infrastrutture, dove l'accesso amico porta a migliore progettazione, il design non peggio.

Il mio esempio è semplice: se una classe A deve fornire un'interfaccia "amico" speciale alla classe B in java, dobbiamo inserirli nello stesso pacchetto. Nessuna eccezione. In tal caso se A è un amico di B e B è un amico di C, A deve essere un amico di C che non è sempre vero. Questa "transitivity amicizia" rompe l'incapsulamento più di ogni problema che l'amicizia C++ potrebbe portare a.