Come nascondere la dipendenza di implementazione di AOP senza interrompere l'incapsulamento?

7

Ho il concetto di una cosa SlowLoading :

public interface SlowLoading {
  boolean hasLoaded();
}

Ho anche un componente MyComponent :

public interface myComponent{
  void doSomething();
}

La mia implementazione copre entrambi:

public class MyComponentImpl implements SlowLoading, MyComponent {
   // omitted for brevity
}

Ho un contenitore (interfaccia omessa per brevità) che restituisce MyComponent :

public class MyContainerImpl implements MyContainer{
  @Inject private MyComponent component;

  @Override    
  public MyComponent doSomething(){
    // magic happens
    return myComponent;
  }
}

Ho anche un componente AOP che intercetta il ritorno del caricamento lento delle cose e attende implicitamente che vengano caricate prima di tornare:

@Pointcut("execution(SlowLoading+ *(..) )")
  public void returnsSlowLoadingThing() {
}

Tuttavia, al momento il metodo MyContainer non è proxy, poiché il valore restituito non implementa SlowLoading .

Qual è il modo migliore per incapsulare questo comportamento?

Opzioni che ho considerato:

  • Crea MyComponent estendi SlowLoading . Questo sembra un odore di codice e la rottura di incapsulamento - implementazione sanguinante nell'interfaccia. A un cliente non interessa se è lento o meno.
  • Inietta MyComponentImpl direttamente nel mio contenitore e restituiscilo esplicitamente (restituzioni in co-variante). Ancora una volta, sembra che stia rompendo l'incapsulamento e il punto di programmazione delle interfacce, ma si sente meglio di quanto sopra, dal momento che è fatto a un livello inferiore e nascosto dietro l'interfaccia (dettagli di implementazione). Tuttavia sta rompendo l'incapsulamento della funzionalità AOP che dovrebbe essere ortogonale e trasparente.
  • Esegui l'attesa AOP prima di richiamare un metodo su una cosa SlowLoading . Questo sembra il più appropriato, ma non sono stato in grado di farlo funzionare così lontano.
posta Tim 15.05.2014 - 04:58
fonte

2 risposte

1

Che ne dici di intercettare ogni sottoclasse Method of Container che restituisce oggetti?

Il vantaggio di questo approccio è che le tue interfacce principali non hanno bisogno di nulla sul concetto di "SlowLoading". Uno svantaggio d'altra parte è che puoi intercettare più chiamate del necessario - il che può o meno un problema per il tuo caso d'uso.

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TransparentLoading {

    @Pointcut("execution(public Object+ Container.*(..))")
    public void executionOfObjectReturningContainerMethod(){}

    @Around("executionOfObjectReturningContainerMethod()")
    public Object performLazyLoadingIfNecessary(ProceedingJoinPoint joinPoint) throws Throwable{

        Object result = joinPoint.proceed();

        if(result instanceof SlowLoading){
            result = ensureLoaded((SlowLoading)result);
        }

        return result;
    }

    public static Object ensureLoaded(SlowLoading result) {

        if(!result.isLoaded()){
            result.load();
        }

        return result;
    }
}
    
risposta data 18.07.2014 - 18:16
fonte
0

Penso che questo non sia il miglior esempio di AOP.

Sembra che dovrebbe interrompere l'incapsulamento, possibili soluzioni alternative potrebbero essere:

A. Usa altre 2 interfacce che coprono i 2 casi di SlowLoading (aspetta o non aspetta) e usa una di queste interfacce in AOP cut

B. Non utilizzare affatto AOP per questa funzionalità e utilizzare 2 interfacce (come sopra) che gestiscono diversi casi di SlowLoading (attesa e blocco o non-attesa e proxy). Ciò farebbe anche uso di alcuni pattern factory per ottenere l'istanza SlowLoading corretta (attesa o non-block)

    
risposta data 23.05.2014 - 13:23
fonte

Leggi altre domande sui tag