2009-02-27 6 views

risposta

18

Posso pensare a un altro utilizzo rispetto a quelli collegati da Eric P: definire un'implementazione predefinita/non operativa dell'interfaccia.

./alex

interface IEmployee 
{ 

    void workHard(); 
    void procrastinate(); 

    class DefaultEmployee implements IEmployee 
    { 
     void workHard() { procrastinate(); }; 
     void procrastinate() {}; 
    } 

} 

Ancora un altro esempio - attuazione Null Object Pattern:

interface IFoo 
{ 
    void doFoo(); 
    IFoo NULL_FOO = new NullFoo(); 

    final class NullFoo implements IFoo 
    { 
     public void doFoo() {}; 
     private NullFoo() {}; 
    } 
} 


... 
IFoo foo = IFoo.NULL_FOO; 
... 
bar.addFooListener (foo); 
... 
+0

Ooh, mi piace questa idea. – Herms

+0

@Totophil: felice che tu abbia avuto l'idea e grazie per aver migliorato la mia risposta. @Herms: contento che ti piaccia! – alexpopescu

+1

Comunemente Null Object può anche essere un singleton dato che non mantiene nessuno stato e non muta altri oggetti - questa è in realtà una grande risposta dato che inizierò a fare cose come questa d'ora in avanti, questo è intelligente! – Esko

5

posso dire senza esitazione che non ho mai fatto questo. Non riesco a pensare a una ragione per cui lo faresti neanche tu. Le classi sono annidate all'interno delle classi? Certo, molte ragioni per farlo. In questi casi tendo a considerare quelle classi interne come un dettaglio di implementazione. Ovviamente un'interfaccia non ha dettagli di implementazione.

8

Penso che this page spiega un esempio abbastanza bene. Lo useresti per legare strettamente un determinato tipo a un'interfaccia.

spudoratamente strappato dal link qui sopra:

interface employee{ 
    class Role{ 
      public String rolename; 
      public int roleId; 
    } 
    Role getRole(); 
    // other methods 
} 

Nella interfaccia di cui sopra si sono vincolanti digitare il ruolo fortemente all'interfaccia dipendente (employee.Role).

2

Suppongo che si possa definire una classe che viene utilizzata come tipo di ritorno o tipo di parametro per i metodi nell'interfaccia. Non sembra particolarmente utile. Si potrebbe anche solo definire la classe separatamente. L'unico vantaggio possibile è che dichiara la classe come "appartenente" all'interfaccia in un certo senso.

1

Questa operazione sembra avere "una cattiva decisione di progettazione" scritta dappertutto.

1

esorto cautela ogni volta che sembra una buona idea per creare una classe non-privato nidificato. Quasi sicuramente stai andando meglio per una classe esterna. Ma se si intende creare una classe nidificata pubblica, non sembra più strano inserirla in un'interfaccia rispetto a una classe. L'astrattezza della classe esterna non è necessariamente correlata all'astratto di una classe annidata.

2

Google Web Toolkit utilizza tali classi di legare l'interfaccia 'normale' per asincrona interfaccia di richiamo:

public interface LoginService extends RemoteService { 

    /** 
    * Utility/Convenience class. 
    * Use LoginService.App.getInstance() to access static instance of LoginServiceAsync 
    */ 
    class App { 

     public static synchronized LoginServiceAsync getInstance() { 
      ... 
     } 
    } 
} 
6

Un uso (bene o male) sarebbe come una soluzione per il fatto che Java non supporta metodi statici nelle interfacce.

interface Foo { 
    int[] getData(); 

    class _ { 
     static int sum(Foo foo) { 
      int sum = 0; 
      for(int i: foo.getData()) { 
       sum += i; 
      } 
      return sum; 
     } 
    } 
} 

Poi si definirebbe con:

int sum = Foo._.sum(myFoo); 
+0

È molto peggio che devo votare. Adoro questo tipo di esperimenti. – akuhn

+1

Mi stai prendendo in giro. Loro lo hanno compilato ???!?!? (simpatico, btw) – Overflown

3

Un posto questo idioma è usato pesantemente è in XMLBeans. Lo scopo di tale progetto è di prendere uno schema XML e generare un set di classi Java che è possibile utilizzare in modo bidirezionale per lavorare con i documenti XML corrispondenti allo schema. Quindi, consente di analizzare XML in bean xml o creare i bean xml e di output in xml.

In generale, la maggior parte dei tipi di schemi xml sono mappati su un'interfaccia Java.Quella interfaccia ha al suo interno una fabbrica che viene utilizzato per generare istanze di tale interfaccia nella implementazione di default:

public interface Foo extends XmlObject { 
    public boolean getBar(); 
    public boolean isSetBar(); 
    public void setBar(boolean bar); 

    public static final SchemaType type = ... 

    public static final class Factory { 
    public static Foo newInstance() { 
     return (Foo)XmlBeans.getContextTypeLoader().newInstance(Foo.type, null); 
    } 

    // other factory and parsing methods 
    } 
} 

Quando ho incontrato prima questo mi è sembrato sbagliato legare tutto questo gunk implementazione nella definizione dell'interfaccia. Tuttavia, in realtà mi piaceva perché lasciava che tutto fosse definito in termini di interfacce, ma aveva un modo uniforme per ottenere istanze dell'interfaccia (invece di avere un'altra classe factory/builder esterna).

L'ho preso per le classi in cui ciò aveva senso (in particolare quelli in cui avevo un grande controllo sull'interfaccia/impls) e l'ho trovato abbastanza pulito.

1

Questo approccio può essere utilizzato per definire molte classi nello stesso file. Questo ha funzionato bene per me in passato, dove ho molte implementazioni semplici di un'interfaccia. Tuttavia, se dovessi farlo di nuovo, userei un enum che implementa un'interfaccia che sarebbe stata una soluzione più elegante.

+0

nascondi i commenti Stavo pensando anche all'implementazione attraverso enum, ma dal momento che ogni enum è effettivamente una raccolta di singletons mi stavo sforzando di pensare a qualsiasi esempio di vita reale in cui qualcuno vorrebbe un gruppo di "default" singleton che implementano per la stessa interfaccia. –

2

Con una classe statica all'interno di un'interfaccia, è possibile abbreviare un frammento di programmazione comune: verificare se un oggetto è un'istanza di un'interfaccia e, in tal caso, chiamare un metodo di questa interfaccia. Guarda questo esempio:

public interface Printable { 
    void print(); 

    public static class Caller { 
     public static void print(Object mightBePrintable) { 
      if (mightBePrintable instanceof Printable) { 
       ((Printable) mightBePrintable).print(); 
      } 
     } 
    } 
} 

Ora, invece di fare questo:

void genericPrintMethod(Object obj) { 
    if (obj instanceof Printable) { 
     ((Printable) obj).print(); 
    } 
} 

si può scrivere:

void genericPrintMethod(Object obj) { 
    Printable.Caller.print(obj); 
}