2014-12-20 21 views
5

Here mi sono imbattuto in questa frase:interfacce privato all'interno di una classe

Implementare un'interfaccia privata è un modo per forzare la definizione di i metodi che si interfacciano senza l'aggiunta di alcuna informazione di tipo (cioè, senza permettere qualsiasi upcasting).

Sto trovando difficile capire questo. Qualcuno può spiegarlo per me?

+0

Possibilmente già risposto qui http://stackoverflow.com/questions/4573713/design-decisions-why-and-when-to-make-an-interface-private – emeraldjava

+0

@emeraldjava : Ho visto quella domanda Ma non chiarisce questa frase o non riuscivo a capirlo. Potresti indicarmi una sezione o una frase pertinente? –

risposta

1

Gli esempi nell'articolo collegato sono un po 'artificiali e artificiali (come già indicato dai nomi dispari, A, B ecc ...). Tuttavia, concentriamoci sulla parte della citazione che la tua domanda si riferisce a:

"... senza aggiungere alcuna informazione di tipo (cioè, senza permettere alcun upcasting)."

La classe può offrire più implementazioni (pubbliche o private) di questa interfaccia. Ma il punto chiave è:

Nessuno sarà mai in grado di capire che implementano questa interfaccia.

Semplicemente, perché l'interfaccia non è pubblica.

Ho provato a creare un esempio che mostra un possibile caso di applicazione.Certo, è ancora artificioso, ma potrebbe rendere il punto più ovvio. Si consideri che si desidera modellare una struttura dati Tree, costituita da oggetti Node. Questi possono essere oggetti InnerNode (che hanno nodi figlio) o oggetti LeafNode (che non hanno figli).

Tale classe potrebbe essere implementata in questo modo:

class Tree { 

    // The private interface 
    private interface Node { 
     List<Node> getChildren(); 
    }  

    // Both are public implementations 
    public class InnerNode implements Node { 
     @Override 
     public List<Node> getChildren() { 
      return Arrays.<Node>asList(getLeafNode(), getLeafNode()); 
     } 
    } 
    public class LeafNode implements Node { 
     @Override 
     public List<Node> getChildren() { 
      return Collections.emptyList(); 
     } 
    } 

    // These return the concrete, public types 
    public InnerNode getInnerNode() { return new InnerNode(); } 
    public LeafNode getLeafNode() { return new LeafNode(); } 

    // This returns the private interface type 
    public Node getRootNode() { 

     // Both concrete types can be returned here, 
     // because they both implement the interface 
     return getInnerNode(); // Works 
     //return getLeafNode(); // Works 
    } 

    // This uses only the interface type 
    public void traverseNode(Node node) { 
     System.out.println("Traversing "+node); 
     for (Node child : node.getChildren()) { 
      traverseNode(child); 
     } 
    } 
} 

In un metodo esterno main, si possono osservare le limitazioni imposte dall'interfaccia privato:

public static void main(String[] args) { 
    Tree tree = new Tree(); 

    // The public concrete types can be used 
    Tree.LeafNode leafNode = tree.getLeafNode(); 
    Tree.InnerNode innerNode = tree.getInnerNode(); 

    // The private interface can not be used from outside: 
    //Tree.Node node = tree.getRootNode(); 

    // This is possible: The class only uses its 
    // own private interface here 
    tree.traverseNode(tree.getRootNode()); 
} 

In questo esempio, si può chiamare traverseNode, passando il Node restituito da getRootNode, indipendentemente dal fatto che questo nodo sia un InnerNode o un LeafNode. Nella versione attuale, questo stampa qualcosa come

Traversing Tree$InnerNode 
Traversing Tree$LeafNode 
Traversing Tree$LeafNode 

Se è stata modificata getRootNode di restituire un LeafNode, allora sarebbe solo stampare

Traversing Tree$LeafNode 

Per dirla semplicemente, e come il nome "l'interfaccia privata" suggerisce già: È possibile utilizzare questo per nascondere il fatto che due classi condividono un antenato comune.

0

Un'interfaccia privata è un modo per forzare una classe a implementare alcuni metodi, senza esporre pubblicamente che questa interfaccia è implementata - ad esempio, non sarà possibile creare un List<MyPrivateInterface> e aggiungere istanze della classe.

+0

Sì, è vero. Ma come potrebbe chiarire che quando vengono utilizzate le interfacce private, questo ci permette di evitare "l'aggiunta di qualsiasi tipo di informazione (cioè, senza consentire alcun upcasting)." Questo è quello che sto cercando di capire. Grazie per il vostro chiarimento. –

+1

Significa semplicemente che se si ha "Foo.Bar" come interfaccia privata e un oggetto di tipo "Foo.Baz implementa Foo.Bar", quindi il codice al di fuori di "Foo" può usare quell'oggetto come un'istanza di " Baz', ma non può (su) lanciarlo su 'Bar'. Nota abbastanza ovvia, davvero. Penso che la ragione per cui non capisci è che stai cercando un significato nascosto, che semplicemente non c'è. – Dima

+0

Penso che non sappia cosa significa upcasting. – niceman

0

Penso che la domanda sia perché si vorrebbe "forzare" la propria classe implementare qualcosa? Voglio dire, è la tua classe, se vuoi implementare un metodo, basta implementarlo. "Interfaccia privata" è solo un termine improprio. Un'interfaccia è la vista della tua classe che vuoi esporre all'esterno. Rendendolo privato non serve a nulla.

Se stai chiedendo informazioni sulle interfacce "pacchetto privato", è un po 'diverso, anche se non molto. A volte potresti voler implementare un'interfaccia, che è interna alla tua implementazione e non è esposta all'esterno. È piuttosto difficile (anche se non impossibile) trovare un esempio in cui sarebbe utile.

+0

Sì. Accetto il fatto che le interfacce private siano un po '"improprie". Volevo solo assicurarmi di averlo capito correttamente. Forse sto perdendo il senso di usare "interfacce private". –

4

Ecco un esempio di interfacce private.

public class Main { 

    private interface Animal { 
     void makeNoise(); 
    } 

    public static final class Cow implements Animal { 
     @Override 
     public void makeNoise() { 
      System.out.println("Moo!"); 
     } 
    } 

    public static final class Sheep implements Animal { 
     @Override 
     public void makeNoise() { 
      System.out.println("Bah!"); 
     } 
    } 

    public static void main(String[] args) { 
     List<Animal> animals = Arrays.asList(new Cow(), new Sheep()); 
     for (Animal animal : animals) 
      animal.makeNoise(); 
    } 
}  

dall'interno della classe Main è possibile fare riferimento a un Animal e chiamare makeNoise() su di esso. Pertanto è possibile avere uno List di Animal s di tipi diversi e utilizzare a ogni ciclo per chiamare makeNoise() su tutti.

Tuttavia, al di fuori della classe Main non è possibile. È possibile avere un Cow o un Sheep e chiamare makeNoise() su entrambi, ma l'interfaccia Animal e il metodo di interfaccia makeNoise() non sono visibili.

+0

Grazie per il tuo esempio. Sebbene sia "poco" usato, l'astrazione è abbastanza potente e questo riduce le dipendenze generali nella progettazione e crea un potenziale per il riutilizzo. –

+0

@tharindu_DG Ho modificato la mia risposta. Quest'ultima frase (ora cancellata) era una questione di opinione. –

+0

Sì ..! Praticamente la tua opinione sembra essere corretta. Ma non è logico evitare di utilizzare interfacce private. Le opinioni possono essere diverse, le discussioni sono benvenute. Grazie per i tuoi pensieri. –

1

Ho esaminato questo problema e sono in grado di trovare alcune informazioni su . Il seguente è un esempio pratico

enter image description here

La classe SaveInterface è un tipo (cioè una classe senza attuazione, tutti i suoi metodi sono astratti). Ha una funzione membro pubblica chiamata SaveData(). La classe di documento dalla soluzione iniziale implementa ora il tipo SaveInterface in un modo che impedisce al metodo SaveData() di essere accessibile ai client del documento .

Si noti che, in questa soluzione, SaveHandler non ha un'associazione navigabile con la classe Documento con . Questa è stata sostituita con una associazione navigabile alla classe SaveInterface . Poiché SaveData() è dichiarato pubblicamente nella classe SaveAndler SaveHandler, non è necessario dichiararlo come amico della classe Documento di .

Poiché la classe SaveHandler non è un amico della classe Documento, non ha la possibilità di modificare nessuna delle sue variabili membro private o di chiamare nessuna delle sue funzioni membro private . Quindi l'incapsulamento della classe Document è stato preservato. La classe SaveHandler non ha più nemmeno bisogno di conoscere la classe Documento poiché ora dipende da un'interfaccia chiamata SalvaInterfaccia. Ciò riduce le dipendenze generali di nella progettazione e crea un potenziale per il riutilizzo.

partecipanti

Target (documento)

  • definisce l'interfaccia pubblica per il cliente.
  • costruisce l'oggetto RequestHandler (SaveHandler) e passa a RequestHandler un'istanza della classe RequestInterface (SaveInterface). - nell'esempio motivante, la classe Documento esporta un'interfaccia che consente ai client di avviare i salvataggi asincroni.

client

  • client utilizzano l'interfaccia di destinazione esportato per eseguire specifiche funzioni .

Comando

  • l'interfaccia di comando è impiegato perché è probabile che l'interfaccia target vorrà per creare diversi tipi di oggetti RequestHandler. Se tutti questi oggetti implementano l'interfaccia Comando , è possibile utilizzare un Factory2 per creare i singoli oggetti RequestHandler .

RequestHandler (SaveHandler)

  • creato con un riferimento al RequestInterface. implementa l'interfaccia di comando in modo che la classe di destinazione possa chiamare la funzione membro Execute() per eseguire la richiesta.

  • nell'esempio motivare la classe SaveHandler viene utilizzato per creare un thread separato di esecuzione e quindi chiamare una funzione membro definita nel SaveInterface salvare effettivamente i dati nel Documento nella filo appena creato.

RequestInterface (SaveInterface)

  • specifica un'interfaccia astratta per una particolare richiesta.

enter image description here

Conosciuto Utilizza

Questo modello è usato ampiamente in un ambiente real-time embedded a Xerox. È utilizzato per interrompere il thread di esecuzione in classi che eseguono vari servizi per i propri client.

Per maggiori informazioni: http://www.objectmentor.com/resources/articles/privateInterface.pdf

Problemi correlati