Esistono lingue che consentono al contesto statico di una chiamata al metodo di essere disponibile in fase di runtime?

6

È possibile che un metodo conosca il tipo di metodo in cui è chiamato? Così, ad esempio, nel seguente codice psuedo orientato agli oggetti:

Instance io = new InstanceSubclass();
io.doStuff();

Esiste un linguaggio che consente a doStuff() di sapere che è stato chiamato come Instance ?

La domanda è nata dal fatto che Java non fornisce alcun tipo di supporto per le interferenze dei nomi di interfaccia, ad esempio se si crea una classe che implementa le interfacce A e B che hanno entrambe una firma del metodo come void doWork() essere possibile per il corpo di doWork() di fare qualcosa di simile al seguente:

public void doWork() {
    Class<?> context = getMethodCallContext();
    if(context == InterfaceA.class) {
        doAsInterfaceA();
    }
    else if(context == InterfaceB.class) {
        doAsInterfaceB();
    }
    else {
        // Shenanigans and error handling
    }
}

Non ho intenzione di scrivere alcun codice che sfrutti questa caratteristica in modo da farlo trasudare un anti-pattern in attesa di accadere, voglio solo sapere se può essere fatto, in caso affermativo quali lingue lo consentono?

    
posta ahjmorton 02.01.2012 - 02:35
fonte

4 risposte

3

In C # basta:

 void InterfaceA.doWork()
 {
 }

 void InterfaceB.doWork()
 {
 }

Quindi non ci sono veri shenanigans coinvolti.

La funzione chiamante deve identificare quale doWork() è intesa:

Instance io = new InstanceSubclass();
((InterfaceA)io).doStuff();

Vedi questa pagina per ulteriori dettagli .

    
risposta data 02.01.2012 - 03:06
fonte
5

Ciò che hai descritto è raggiungibile tramite la programmazione orientata agli aspetti (AOP). Non sarà così semplice come nel tuo esempio, ma puoi ottenere il comportamento richiesto.

AOP ha implementazioni in diverse lingue; AspectJ è uno dei più maturi. Ti darò un esempio usando AspectJ anche se non voglio entrare troppo nei dettagli.

Per implementare il comportamento:

1) Crea un collegamento che intercetterà tutte le chiamate al metodo public void doWork() .
[ pointcut conflictingMethodIsExecuted(): execution(public void doWork() ]

2) Crea un consiglio intorno a questo punto. All'interno del consiglio, puoi ottenere il contesto; proprio come hai specificato nel tuo esempio. Il JoinPoint ti fornirà tali informazioni.
[ joinPoint.getThis() // returns the context ]

3) Con queste informazioni, il consiglio imposta un determinato parametro e lascia correre public void doWork() . Il metodo dà un'occhiata a quel parametro e decide cosa fare.

Presumo che la domanda fosse un po 'teorica quindi anche questa risposta segue la stessa linea. Posso fornire maggiori dettagli sulla soluzione in AspectJ se si sceglie di intraprendere questa strada.

    
risposta data 02.01.2012 - 03:18
fonte
1

Non vedo il nome del metodo dell'interfaccia in conflitto qui. Ci sarebbe uno scontro nel caso dell'ereditarietà multipla, ma questa è una relazione di classe diversa.

Nel tuo esempio hai due interfacce che richiedono entrambi l'implementazione di un metodo doWork vuoto senza parametri. Ciò che il metodo deve fare deve essere indipendente da quale interfaccia è utilizzata per chiamare il metodo. Se c'è un conflitto, allora si trova nella specifica dell'interfaccia, o nel design della classe per usare le due interfacce con aspettative differenti sul metodo doWork.

Le firme dei metodi più complicate potrebbero portare a metodi con lo stesso nome ma firme diverse, nel qual caso la firma verrebbe utilizzata per differenziare i due metodi.

    
risposta data 02.01.2012 - 03:06
fonte
0

È possibile ottenere esattamente questo effetto in Java sovraccaricando un metodo:

  public void doStuff(InterfaceA object) {
    // stuff for InterfaceA
  }

  public void doStuff(InterfaceB object) {
    // stuff for InterfaceB
  }

E chiamalo come segue:

  if (object instanceof InterfaceA) {
    doStuff((InterfaceA)object)
  } 
  else if (object instanceof InterfaceB) {
    doStuff((InterfaceB)object);
  }

Anche questo è abbastanza performante: tutte le chiamate saranno determinate staticamente dal compilatore in modo da avere solo l'istanza di / overhead di casting (che è piuttosto minimale).

    
risposta data 02.01.2012 - 17:19
fonte