E 'possibile rendere alcuni metodi invisibili / non utilizzabili per alcune classi in Java?

2

Sto sviluppando un'applicazione in Java per cui vorrei passare un oggetto come parte di un'interfaccia in altri metodi di classi scritti da altri sviluppatori nel team. L'oggetto che sto passando ha setter e getter nel modo normale, ma non voglio che alcune delle classi scritte da altri accedano ad alcuni dei setter dell'oggetto passato (diversi setter sarebbero disponibili per classi diverse quando usa l'oggetto). È possibile in Java? vale a dire quali classi possono utilizzare quali metodi in altre classi su una base per classe?

Immagino che cosa mi piacerebbe fare è qualcosa come:

someObject.method(passInObject[but don't give access to passInObject.thisSetter])

Dove "someObject" è un oggetto di una classe scritta da un membro del team e "passInObject" è un oggetto della mia classe ma voglio proteggere alcuni dei membri in essa contenuti da questa specifica classe someObject.

Sto indovinando no e avrò bisogno di usare l'ereditarietà per scavalcare quei setter che non voglio che altri moduli specifici usino / vedano, ma sembra clunky avere una nuova classe ereditata per usare la classe basata sulla protezione di alcuni interni valori solo da alcuni usando classi. Potrei controllare il codice che il valore di un membro non è stato modificato, ma è troppo tardi e il danno è stato fatto (la cancellazione potrebbe essere costosa). Potrei controllare il nome della classe nel metodo setter stesso e non fare nulla se il nome è su un elenco "vietato", ma sembra molto goffo e incline agli errori. Quello che voglio è il codice chiamante per limitare quali membri possono essere chiamati nell'oggetto passato.

O mi manca qualcosa e c'è un modello comune per affrontare questo?

    
posta David Scholefield 26.01.2015 - 12:57
fonte

5 risposte

8

Questo non può essere fatto. I tuoi problemi nascono dalla violazione di ISP .

Detto questo, l'unica idea che riesco a pensare è di forzare le classi client a registrarsi con le classi in ordine per poter chiamare i loro metodi o ottengono un NotRegisteredException . Una volta registrati, puoi controllare il loro tipo e aumentare un YouAreNotAllowedToCallThisMethodException se la classe registrata non è in un elenco di classi consentite.

Questa è una soluzione molto poco elegante e preferirei correggere le violazioni dell'ISP separando le interfacce. Ma questo non impedisce ai tuoi colleghi di usare le interfacce che non vuoi che usino.

I seguenti esempi di codice sono da questa grande risposta dall'utente Marjan Venema da un'altra domanda.

interface IEverythingButTheKitchenSink
{
     void DoDishes();
     void CleanSink();
     void CutGreens();
     void GrillMeat();
}

vs

interface IClean
{
     void DoDishes();
     void CleanSink();
}

interface ICook
{
     void CutGreens();
     void GrillMeat();
}
    
risposta data 26.01.2015 - 14:05
fonte
5

Nascondere metodi ereditati è una pessima idea e quasi garantito per causare dolore.

Direi che questo è ciò che Interfacce sono per; un "accordo di divulgazione" tra due o più classi che descrive accuratamente ciò che ciascuno è autorizzato a conoscere sull'altro [s].

Naturalmente, questo otterrà solo un acaro se il suo misto con l'ereditarietà come descriveresti - la tua classe base dovrebbe implementare l'Interfaccia o ogni classe derivata dovrebbe farlo da sola? YMMV.

    
risposta data 26.01.2015 - 13:11
fonte
2

Non puoi fare esattamente quello che vuoi - vedi le altre risposte, ma ci sono un paio di cose che potresti fare.

  1. Potresti avere un'interfaccia privata del pacchetto che espone i setter e un'interfaccia pubblica che espone i getter.
    • Hai detto che vuoi usare i setter in più pacchetti nel tuo codice. Perchè è questo? Questo è un odore di codice per me - se il tuo codice potrebbe interferire con il funzionamento interno di una classe al di fuori del pacchetto in cui è definita la classe, sembra che tu sia rompendo l'incapsulamento e dovresti prendere in considerazione il refactoring.
  2. Potresti avere un oggetto builder / factory che rilascia istantanee immutabili di queste classi.
    • Questo è l'approccio preferito , specialmente se l'applicazione utilizza il codice multithread. La creazione di un POJO che contiene tutti i dati (ma nessuna delle mutabilità) della tua classe originale aggiungerà la sicurezza che desideri inoltre, renderà il codice molto più facile da eseguire il debug in seguito.

Indipendentemente da ciò che fai, spendendo un po 'di energia nel limitare le situazioni in cui gli oggetti condivisi possono mutare, specialmente al di fuori del pacchetto, entrambi aiuteranno ad affrontare questo problema e renderanno più facile il tuo mantenimento in seguito.

Ulteriori letture:

risposta data 26.01.2015 - 15:47
fonte
0

Ci sono molti modi per farlo in Java, a seconda del tuo scenario specifico.

Da una parte, potremmo iniziare ad analizzare se i modificatori di accesso potrebbero aiutare in questo scenario.

Ad esempio, in Java è possibile utilizzare il pacchetto per modulare il codice.

package a;

public class A {
   private String foo;
   public String getFoo(){ return this.foo; }
   void setFoo(String foo){ this.foo = foo; }
}

Nel codice precedente, solo le classi nel pacchetto A sarebbero mai autorizzate ad accedere al metodo setFoo poiché è definito con un accesso a livello di pacchetto, ma tutti potrebbero invocare getFoo() poiché è pubblico.

Se sai che gli utenti della tua classe saranno in un pacchetto diverso (che è lo scenario più tipico) di quello che potrebbe funzionare perfettamente per te. Usa il pacchetto per definire i tuoi moduli coesivi ed esporre solo ciò che vuoi essere esposto.

Se vuoi nascondere la funzionalità per i membri del tuo pacchetto, è probabile che qualcosa potrebbe essere sbagliato con il design, forse hai bisogno di un subpackage o usi più interfacce come suggerito nell'altra risposta.

    
risposta data 26.01.2015 - 14:06
fonte
0

È possibile che il tuo errore stia adottando un approccio di accesso troppo dettagliato. Sei sicuro che ogni utente della tua classe avrà un accesso diverso? Forse il tuo problema attuale è che dovresti implementare un meccanismo Role in cui solo un utente con un ruolo specifico può avere accesso a determinati metodi.

Un meccanismo Role può essere implementato utilizzando interfacce diverse o anche utilizzando un Proxy per controllo reale a grana fine.

    
risposta data 26.01.2015 - 16:22
fonte

Leggi altre domande sui tag