Search code examples
c#design-patternsconsole-applicationobserver-patternstrategy-pattern

When a variable change in a C# console application, the connection automatically change


Consider:

Console.WriteLine("Set firstValue");
decimal first = Convert.ToDecimal(Console.ReadLine());

first variable

Console.WriteLine("Set Changeable Value");
decimal changeable = first + 5;

The second value depends on the first value:

Console.WriteLine("Set firstValue again");
first = Convert.ToDecimal(Console.ReadLine());

When changing the first value, change automatically changeable value. But I want to use the observer and strategy design pattern and really I mess up.


Solution

  • There is an example of the observer pattern in C# on Wikipedia:

    public class Payload
    {
        public string Message { get; set; }
    }
    
    public class Subject : IObservable<Payload>
    {
        public IList<IObserver<Payload>> Observers { get; set; }
    
        public Subject()
        {
            Observers = new List<IObserver<Payload>>();
        }
    
        public IDisposable Subscribe(IObserver<Payload> observer)
        {
            if (!Observers.Contains(observer))
            {
                Observers.Add(observer);
            }
            return new Unsubscriber(Observers, observer);
        }
    
        public void SendMessage(string message)
        {
            foreach (var observer in Observers)
            {
                observer.OnNext(new Payload { Message = message });
            }
        }
    }
    
    public class Unsubscriber : IDisposable
    {
        private IObserver<Payload> observer;
        private IList<IObserver<Payload>> observers;
        public Unsubscriber(IList<IObserver<Payload>> observers, IObserver<Payload> observer)
        {
            this.observers = observers;
            this.observer = observer;
        }
    
        public void Dispose()
        {
            if (observer != null && observers.Contains(observer))
            {
                observers.Remove(observer);
            }
        }
    }
    
    public class Observer : IObserver<Payload>
    {
        public string Message { get; set; }
    
        public void OnCompleted()
        {
        }
    
        public void OnError(Exception error)
        {
        }
    
        public void OnNext(Payload value)
        {
            Message = value.Message;
        }
    
        public IDisposable Register(Subject subject)
        {
            return subject.Subscribe(this);
        }
    }
    

    Below is a test of the above code in action.

    private void TestObserver()
    {
        var subjectState1 = "Initial Update";
        var subjectState2 = "Second Update";
        var subjectState3 = "Last Update";
    
        var subject = new Subject();
    
        subject.SendMessage(subjectState1);
    
        Log("Updated subject to '" + subjectState1 + "'");
    
        var observer1 = new Observer.Observer();
        var observer2 = new Observer.Observer();
    
        var ob1Unobserve = subject.Subscribe(observer1);
        var ob2Unobserve = subject.Subscribe(observer2);
    
        Log("Ob1 val: " + observer1.Message);
        Log("Ob2 val: " + observer2.Message);
    
        subject.SendMessage(subjectState2);
    
        Log("Updated subject to '" + subjectState2 + "'");
        Log("Ob1 val: " + observer1.Message);
        Log("Ob2 val: " + observer2.Message);
    
        ob1Unobserve.Dispose();
        ob2Unobserve.Dispose();
    
        subject.SendMessage(subjectState3);
    
        Log("Updated subject to '" + subjectState3 + "'");
        Log("Ob1 val: " + observer1.Message);
        Log("Ob2 val: " + observer2.Message);
    }
    

    I noticed that the initial state is not sent to the observer on subscribe, which if you need it, can be implemented as such.

    Inside the Subject class, I added the following:

    I added a property for CurrentState:

    public string CurrentState { get { return currentState; } }
    private string currentState = null;
    

    Inside of SendMessage I cache the current state:

    currentState = message;
    

    Inside Subscribe, I push the current state to the subscribing observable:

    observer.OnNext(new Payload { Message = currentState });