AutoFac IoC, DDD и зависимости между репозиториями - PullRequest
5 голосов
/ 27 апреля 2011

У меня есть два типа POCO, A и B. У меня есть репозиторий для каждого, Rep <A> и Rep <B>, оба из которых реализуют IRep <A> и IRep <B>, обслуживаемыеконтейнер IoC (в данном случае AutoFac).

Существует несколько типов репозиториев: загрузка по требованию из БД (или что-то еще), отложенные коллекции в памяти, кэшированные результаты веб-службы,и т.д. Абоненты не могут отличить.И Rep <A>, и Rep <B> оказываются коллекциями в памяти, поскольку A и B не сильно меняются и живут долго.

Одним из свойств B является AЧто я делаю сейчас, когда B запрашивает свой A, B получает IRep <A>, чтобы найти свой A и возвращает его.Он делает это каждый раз - каждый запрос для B's A включает IRep <A>. Find ().Положительным моментом является то, что B никогда не удерживает A, и каждый запрос учитывает, каким бы ни было состояние Rep.Недостатком является большой IoC / IRep <A> отток.

Я думаю об использовании здесь паттерна Lazy <T>, чтобы B однажды спросил IRep <A> и удержал то, что онполучил.Но что произойдет, если A будет удален из своего хранилища?

Я ищу чистый способ для Rep <A> уведомить любого, кто заинтересован, когда он изменился.В моем примере некоторые B могут быть удалены, поэтому я бы хотел, чтобы Rep <A> вызывал событие, когда что-то было удалено или добавлено и т. Д. Rep <B> может подписаться на это событие, чтобы очистить любые Bкоторые относятся к А, которые сейчас ушли, и т. д. Как подключить это?

В идеале ничего не меняется при создании Rep <A>.Он не должен знать, кто его слушает, и А можно манипулировать весь день, даже не запуская Реп.

Но когда рождается Реп <B>, ему нужен способ подписаться на Реп <A>событиеВозможно, еще нет живого представителя <A>, но, безусловно, будет один раз, когда у B будет запрошен его A, так что вполне нормально запустить Rep <A>.

В сущности,когда создается Rep <B>, он хочет зарегистрировать себя в Rep <A> для уведомления о событии.Я не хочу загрязнять интерфейс IRep <T>, потому что это не должно иметь значения для всех, кто находится за пределами уровня репозитория.И другим типам репозиториев, возможно, вообще не придется беспокоиться об этом.

Имеет ли это какой-то смысл?

1 Ответ

3 голосов
/ 28 апреля 2011

Что, если вы заставили Rep<A> вернуть «наблюдаемый» объект, который может вычисляться как А, а также имеет подписываемое событие, которое вызывается, когда что-то об этом А изменяется? Просто мысль. Таким образом, вам не нужно проверять обработчики, чтобы убедиться, что их A изменилось; если событие, которое они слушают, запускается, это касается их экземпляра, а не любого другого.

Вы можете кодировать его следующим образом:

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;

Теперь код потребления будет уведомлен, если внутренняя ссылка будет изменена или наблюдаемое удаляется (что также избавляется от внутренней ссылки). Чтобы наблюдаемое также уведомляло потребляющий код, если дочерние ссылки на As изменяются, сама A должна быть наблюдаемой, вызывая событие, обработанное Observable<T>, которое будет «пузыриться» через ReferenceChanged или более специфический обработчик, такой как InstanceDataChanged, (или любой Вы хотите это назвать).

...