2016-12-03 9 views
0

나는 할 일 목록이 있습니다. 그래서 구독 목록에 구독자를 추가합니다. 가입자가 일을 마친 후에는 가입자가 스스로 가입을 해지해야합니다. 가입자가 끝나면 알 수 없습니다. 가입자 만이 그것을 알고 있습니다.구독자 내에서 구독을 취소하는 방법

어떤 디자인 패턴이나 솔루션이 가장 좋을까요?

내가 사용 옵저버 패턴.

은 내 관찰 가능한 :이는 평소와 같이 구현되는 Unsubscirber입니다

internal class EventObserver : IObserver<double> 
{ 
    private IDisposable _unsubscriber; 
    private readonly IReadOnlyList<Event> _events; 

    public EventObserver(IReadOnlyList<Event> events) 
    { 
     _events = events; 
    } 

    public void Subscribe(EventProvider provider) 
    { 
     _unsubscriber = provider.Subscribe(this); 
    } 

    private int _ind; 
    public void OnNext(double timings) 
    { 
     // may move to next event or not. it depends. 
     // _ind++; may execute or not 

     if (_ind == _events.Count) OnCompleted(); // time to unsubscribe it self 
    } 

    public void OnCompleted() 
    { 
     _unsubscriber.Dispose(); 
    } 

    //... 
} 

(많은 관찰자에 0이있을 수 있습니다) :

internal class EventProvider : IObservable<double> 
{ 
    private readonly List<IObserver<double>> _observers = new List<IObserver<double>>(); 

    public IDisposable Subscribe(IObserver<double> observer) 
    { 
     // check if observer exist... 
     _observers.Add(observer); 
     return new Unsubscriber<double>(_observers, observer); 
    } 

    public void OnTimingsRecieved(double timing) // some other event fires this 
    { 
     foreach (var observer in _observers) 
     { 
      observer.OnNext(timing); 
     } 
    }   

    //... 
} 
는 관찰자이다 . 내가 OnNext 이벤트 내부 관찰자를 처리 할 때
internal class Unsubscriber<T> : IDisposable 
{ 
    private readonly List<IObserver<T>> _observers; 
    private readonly IObserver<T> _observer; 

    internal Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer) 
    { 
     _observers = observers; 
     _observer = observer; 
    } 

    public void Dispose() 
    { 
     if (_observers.Contains(_observer)) 
      _observers.Remove(_observer); 
    } 
} 

문제

가 나타납니다. 내가 foreach 루프 내부에 있었기 때문에 컬렉션이 수정되었고 목록에서 삭제 된 요소가 삭제되었습니다.

가입자를 구독 취소 할 상황을 어떻게 처리합니까? 더 좋은 디자인 패턴이 있습니까?


나는 관측 가능하고 관찰자를 사용하는 대신 다른 접근법을 보게됩니다.

이 이벤트가 있다고 가정합니다.

public event EventHandler<double> TimeDiff; 

는 그리고 당신은 TimerDiff에 연결된 가입자의 인스턴스가 자신을 취소 할 수 있습니다.

public class Reciever 
{ 
    Jobs listOfJobsToDo; 

    public void TimeDiffRecieved(double diff) 
    { 
     listOfJobsToDo.DoJob(diff); 
     if(somecondition) 
      Unsubscribe(); 
    } 
} 
+1

왜 당신은 자신의 관측 대상을 구현하고 있습니까? 그것은 위험으로 가득차 있습니다. 내장 된 Rx 구현을 사용해야합니다. – Enigmativity

+1

알겠습니다. 이 관측기를 제거하고 Rx가 시간을내어 어떻게 작동하는지 확인하려고합니다. @Enigmativity –

답변

0

foreach는 내가 루프에 사용했던 변경 사항을 처리합니다.

이 경우 우리는 관찰자가 작업 할 때 스스로 처분 할 수 있다는 것을 알고 있습니다. 다른 것은 영향을받지 않습니다.

다음은 제공 업체에 대한 수정입니다.

public void OnTimingsRecieved(double timing) 
{ 
    for (int i = 0; i < _observers.Count; i++) 
    { 
     var count = _observers.Count; // save count in case it may change. 
     var observer = _observers[i]; 
     observer.OnNext(timing);  // it may only dispose it self. 
     i -= count - _observers.Count; // decrement if observer unsubscribed. 
    } 
} 
+1

이 패턴을 사용하는 경우 Rx (Reactive) 확장명에 해당하는 준비된 솔루션을 더 잘 재사용하십시오. – Evk

+0

가 흥미로운 것 같습니다. 그것은 나를 위해 완전히 새로운 것입니다. 그걸 아프다. 고마워. @Evk –