State pattern in C#

The state design patterns is a behavioral pattern that implements a state machine in an object-oriented way. It allows an object/class to alter its behavior when its internal state changes.

Lets say that we have a competition application that allows clients to register score, but only when the competition is open. A non state pattern design would maybe look like this.

    public interface ICompetition
    {
        int Score { get; }
        void Open();
        void Close();
        void AddScore(int score);
    }

    public class CompetitionWithoutState : ICompetition
    {
        private bool isClosed;
        
        public int Score { get; private set; }

        public void AddScore(int score)
        {
            if (isClosed)
                return;
            this.Score += score;
        }

        public void Close()
        {
            this.isClosed = true;
        }

        public void Open()
        {
            this.isClosed = false;
        }
    }

This may work for the time being, but when we add more and more of different boolean properties we need to check things all over the code and testing will be a pain.

The code below implements the state pattern.

    public interface ICompetition
    {
        int Score { get; }
        void Open();
        void Close();
        void AddScore(int score);
    }

    public interface ICompetitionState
    {
        ICompetitionState AddScore(Action addScore);
        ICompetitionState Closed();
        ICompetitionState Open();
    }

    public class CompetitionWithState : ICompetition
    {
        public ICompetitionState CompetitionState { get; private set; }

        public int Score { get; private set; }

        public CompetitionWithState()
        {
            this.CompetitionState = new OpenCompetition();
        }

        public void Open()
        {
            this.CompetitionState = new OpenCompetition();
        }

        public void Close()
        {
            this.CompetitionState = new ClosedCompetition();
        }

        public void AddScore(int score)
        {
            this.CompetitionState.AddScore(() =>
            {
                Score += score;
            });
        }
    }

    public class OpenCompetition : ICompetitionState
    {
        public ICompetitionState AddScore(Action addScore)
        {
            addScore();
            return this;
        }
        public ICompetitionState Closed() => this;
        public ICompetitionState Open() => this;
    }

    public class ClosedCompetition : ICompetitionState
    {
        public ICompetitionState AddScore(Action addScore) => this;
        public ICompetitionState Closed() => this;
        public ICompetitionState Open()
        {
            return new OpenCompetition();
        }
    }

Yes, it is a lot more code but it will follow the single responsibility principle, and it will be more easy to test.

Leave a Comment

Your email address will not be published. Required fields are marked *