5

Tengo dos tipos POCO, A y B. Tengo un repositorio para cada uno, Rep <A> y Rep <B>, los cuales implementan Irep <A> y Irep <B> servido por un contenedor IoC (AutoFac en este caso).autofac COI, DDD, e inter-repositorio Dependencias

Existen varios tipos de repositorios: carga a pedido desde un DB (o lo que sea), colecciones en memoria de carga diferida, resultados del servicio web en caché, etc. Las personas que llaman no pueden notar la diferencia. Tanto el Rep <A> como el Rep <B> son colecciones en memoria, ya que las A y las B no cambian mucho y viven mucho tiempo.

Una de las propiedades de B es una A. Lo que hago ahora es, cuando se le pide a una B su A, B obtiene IRep <A> para encontrar su A y devolverla. Hace esto cada vez: cada solicitud de B's A implica IRep <A> .Find(). La ventaja es que B nunca se aferra a las A y cada solicitud tiene en cuenta el estado de Rep que sea. La desventaja es una gran cantidad de IoC/IRep <A> churn.

Estoy pensando en utilizar el patrón Lazy <T> aquí para que una B le pregunte a IRep <A> una vez y se aferre a lo que obtuvo. Pero, ¿qué ocurre si se elimina una A de su repositorio?

Estoy buscando una manera limpia para Rep <A> para notificar a quien esté interesado cuando haya cambiado. En mi ejemplo, se puede borrar un cierto B's A, por lo que me gustaría que Rep <A> presente un evento cuando se elimine, agregue, etc. Rep <B> podría suscribirse a este evento para limpiar cualquier B que se refiera a A's que ahora se han ido, etc. ¿Cómo conectarlo?

Lo ideal es que nada cambie al crear una instancia de <A>. No debería tener idea de quién escucha, y los de A podrían manipularse todo el día sin haber encendido nunca un Rep.

Pero cuando nace el Rep <B> necesita una forma de suscribirse al evento Rep <A>. Puede que aún no haya un Rep <A> vivo, pero seguramente habrá una vez que se le solicite a A su B, por lo que parece correcto activar un Rep <A>.

En esencia, cuando se crea una instancia de Rep <B>, quiere que se registre con el Rep <A> para la notificación del evento. No quiero contaminar la interfaz IRep <T> porque esto no debería importar a nadie fuera de la capa del Depósito. Y otros tipos de repositorios pueden no tener que preocuparse por esto en absoluto.

¿Tiene esto sentido?

Respuesta

3

¿Qué pasa si se hace que el Rep<A> devuelva un objeto "observable" que puede evaluarse a una A, y también tiene un evento suscribible que se genera cuando cambia algo sobre esa A? Solo un pensamiento. De esta forma, no es necesario que los controladores comprueben para asegurarse de que su A haya cambiado; si el evento que están escuchando se dispara, se trata de su instancia y no de ninguna otra.

Es posible codificar de la siguiente manera:

public class Observable<T>:IDisposable 
{ 
    private T instance; 
    public T Instance 
    { 
     get{return instance;} 
     set{ 
     instance = value; 
     var handlers = ReferenceChanged; 
     if(handlers != null) handlers(this, instance); 
    } 

    public static implicit operator T(Observable<T> obs) 
    { 
     return obs.Instance; 
    } 

    //DO NOT attach anonymous delegates or lambdas to this event, or you'll cause a leak 
    public event EventHandler<T> ReferenceChanged; 

    public void Dispose() 
    { 
     var handlers = ReferenceChanged; 
     if(handlers != null) handlers(this, null); 
     foreach(var handler in handlers) ReferenceChanged -= handler; 
    } 
} 

public class Rep<T> 
{ 
    private Dictionary<T, Observable<T>> observableDictionary = new Dictionary<T, Observable<T>>(); 

    ... 
    public Observable<T> GetObservableFactory(Predicate<T> criteria) 
    { 
     //criteria should test only uniquely-identifying information 
     if(observableDictionary.Keys.Any(criteria)) 
     return observableDictionary[observableDictionary.Keys.First(criteria)]; 
     else 
     { 
     //TODO: get object from source according to criteria and set to variable queryResult 
     var observable = new Observable<T>{Instance = queryResult}; 
     observableDictionary.Add(queryResult, observable); 
     return observable; 
     } 
    } 
} 

... 

var observableA = myRepA.GetObservable(myCriteria); 
observableA.ReferenceChanged += DoSomethingWhenReferenceChanges; 

Ahora, el código que consume le notificará si se cambia la referencia interna, o se dispone lo observable (que también dispone de la referencia interna).Para que el observable también notifique el código de consumo si las referencias secundarias de As change, A debe ser observable, activando un evento manejado por Observable<T> que lo "burbujeará" a través de ReferenceChanged o un controlador más específico como InstanceDataChanged, (o lo que quieras) llamarlo).

+0

Ooh Me gusta! Tengo que experimentar un poco, pero esta es una gran manera de verlo. Gracias Keith! – n8wrl

Cuestiones relacionadas