Wzorzec obserwator (observer), czy robię to dobrze?

0

Mam wątpliwości co do implementacji wzorca obserwator z całkowitą separacją warstw.

Poniższy przykład nie jest rzeczywistym projektem, a jedynie przykładem obrazującym o co mi chodzi

I mojej solucji posiadam dwie warstwy projektowe:

  • Desktop (views, view models, models)
  • Service biblioteka(z obserwatorami)

Mój view model subjektem zapisującym obserwatorów.

Kod w VM:

    interface ISubject
        {
            void Subscribe(IObserverService observer);
            void Unsubscribe(IObserverService observer);
            void Notify();
        }
    public class MainWindowViewModel : ViewModelBase, ISubject
        {
            private readonly IControlsService _controlsService;
            private readonly IObserverService _observer1;
            private readonly IObserverService _observer2;
            private ArrayList _observers;
    
            public MainWindowViewModel(
            IControlsService controlsService,
            IObserver1 observer1,
            IObserver2 observer2)
            {
                _observer1 = observer1;
                _observer2 = observer2;
    
                ObserverCommand = new DelegateCommand(OnObserverCommand);
    
                InitProgram();
            }
    
            private void InitProgram()
            {
                _observers = new ArrayList();
    
                _observers.Add(_observer1);
                _observers.Add(_observer2);
            }
    
            public List<IObserverService> Observers { get; set; }
    
            private void OnSwitchCommand(object obj)
            {
                if (Jeden == true)
                {
                    UiModel = _controlsService.SwitchOff();
                }
                else
                {
                    UiModel = _controlsService.SwitchOn();
                }
            }
    
            private void OnObserverCommand(object obj)
            {
                SomeValue++;
            }
    
            public void Subscribe(IObserverService observer)
            {
                Observers.Add(observer);
            }
    
            public void Unsubscribe(IObserverService observer)
            {
                Observers.Remove(observer);
            }
    
            public void Notify()
            {
                Observers.ForEach(x => x.Update(SomeValue));
            }
    
            public ICommand ObserverCommand { get; private set; }
    
            private int _someValue;
            public int SomeValue
            {
                get => _someValue;
                set
                {
                    _someValue = value;
                    InformObservers();
                }
            }
    
            private void InformObservers()
            {
                foreach (IObserverService x in _observers)
                {
                    x.Update(SomeValue);
                }
            }
        }

I prosty obserwator:

    public interface IObserverService
        {
            void Update(int someValue);
        }
    public class Observer1 : IObserver1, IObserverService
        {
            public string ObserverName { get; private set; }
            public Observer1(string name)
            {
                this.ObserverName = name;
            }
            public void Update(int someValue)
            {
                MessageBox.Show("New value: " + someValue.ToString() + " for " + ObserverName);
            }
        }

Observer2 jest taki sam jak powyżej.

Obecnie mam wątpliwości jak powinien wyglądać mój konstruktor, jeśli chciałbym utworzyć nowego obserwatora z nazwą, dla przykładu new Observer1("observer1 name"). Czy mój konstruktor powinien wyglądać tak?

    public MainWindowViewModel()
            {
                _observerService = observerService;
                IObserverService observer1 = new ObserverService("name1");
                IObserverService observer2 = new ObserverService("name2");
    
                SwitchCommnad = new DelegateCommand(OnSwitchCommand);
                ObserverCommand = new DelegateCommand(OnObserverCommand);
    
                InitProgram();
            }

Czy to podejście jest poprawne? I da się testować?

0

W czym to jest lepsze od wbudowanych w C# zdarzeń?

0
somekind napisał(a):

W czym to jest lepsze od wbudowanych w C# zdarzeń?

Mogę się mylić ale w eventach chyba łatwiej o wycieki pamięci. Jeśli się mylę to mnie poprawcie :)

2
szydlak napisał(a):
somekind napisał(a):

W czym to jest lepsze od wbudowanych w C# zdarzeń?

Mogę się mylić ale w eventach chyba łatwiej o wycieki pamięci. Jeśli się mylę to mnie poprawcie :)

To jest jedno i to samo, w obu wypadkach masz wyciek jeśli nie odepniesz niepotrzebnego już obserwatora.
A skoro jest to jedno i to samo, po co używać bardziej rozwlekłego zapisu skoro mamy w c# eventy i delegaty?

Swoją drogą klasyczna wersja obserwatora nie do końca się przyjęła, Ralph Johnson w swojej prezentacji 20 lat ze wzorcami projektowymi przyznaje że lepszym pomysłem jest przesyłanie informacji o tym co się zmieniło do obserwatora, niż sytuacja w której to obserwator odpytuje obiekt obserwujący o nowe wartości po otrzymaniu powiadomienia.

Czyli obsługa eventów w WinfForms czy WPF jest najlepszy przykładem poprawnie zaimplementowanego wzorca obserwator zgodnie z tym co oferuje język C#, a nie to co tutaj kombinujesz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1