Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Monday, 28 November 2011

Implementing the gumball machine in a WinForms environment

image

The code behind is only controlling the UI, and all state is handled by the Gumball machine and its’ state classes:  So my event handlers are simply calling the gumball machine context.

public partial class Form1 : Form {
        GumballMachine gumballMachine;
        public Form1() {
            InitializeComponent();
            gumballMachine = new GumballMachine(5);
            var output = gumballMachine.MachineStateHeader();
            output = PutInLineFeeds(output);
            txtOutput.Text = output;
        }

        private void btnInsertQuarter_Click(object sender, EventArgs e) {
            var output = gumballMachine.InsertQuarter();
            output += gumballMachine.MachineStateHeader();
            output = PutInLineFeeds(output);
            txtOutput.Text = output;
        }

        private void txtTurnCrank_Click(object sender, EventArgs e) {
            var output = gumballMachine.TurnCrank();
            output += gumballMachine.MachineStateHeader();
            output = PutInLineFeeds(output);
            txtOutput.Text = output;
        }

        private void btnRefill_Click(object sender, EventArgs e) {
            var output = gumballMachine.Refill(3);
            output += gumballMachine.MachineStateHeader();
            output = PutInLineFeeds(output);
            txtOutput.Text = output;
        }

        private static string PutInLineFeeds(string output) {
            output = output.Replace("\n", "\r\n");
            return output;
        }
    }

Gumball:

public class GumballMachine {
        IState soldOutState;
        IState noQuarterState;
        IState hasQuarterState;
        IState soldState;
        IState winnerState;

        IState state;

        int count = 0;

        public int Count { get { return count; } set { count = value; } }

        public GumballMachine(int numberGumballs) {
            //creating the state instances - one of each
            noQuarterState = new NoQuarterState(this);
            hasQuarterState = new HasQuarterState(this);
            soldState = new SoldState(this);
            soldOutState = new SoldOutState(this);
            winnerState = new WinnerState(this);
            this.count = numberGumballs;
            if (numberGumballs > 0)
                state = noQuarterState;
            else
                state = soldOutState;
        }

        public string InsertQuarter() {
            return state.InsertQuarter();
        }

        public string EjectQuarter() {
            return state.EjectQuarter();
        }

        public string TurnCrank() {
            var output = state.TurnCrank();
            output += state.Dispense();
            return output;
        }

        public string Refill(int i) {
            return state.Refill(i);
        }

        public void SetState(IState state) {
            this.state = state;
        }

        public IState GetState() {
            return state;
        }

        public IState GetNoQuarterState() {
            return noQuarterState;
        }

        public IState GetHasQuarterState() {
            return hasQuarterState;
        }

        public IState GetSoldState() {
            return soldState;
        }

        public IState GetSoldOutState() {
            return soldOutState;
        }

        public IState GetWinnerState() {
            return winnerState;
        }

        public string ReleaseBall() {
            if (count != 0)
                count--;
            return ("A gumball comes rolling out the slot...\n\n");
        }

        public string MachineStateHeader() {
            var result = new StringBuilder();
            result.Append("Mighty Gumball, Inc.");
            result.Append("\nC# Enabled Standing Gumball Model #2005\n");
            result.Append("Inventory: " + count + " gumball");
            if (count != 1) {
                result.Append("s");
            }
            result.Append("\nMachine is " + state.ToString());

            return result.ToString();
        }
    }

    public class NoQuarterState : IState {
        //a reference to the gumballMachine
        GumballMachine gumballMachine;

        public NoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            gumballMachine.SetState(gumballMachine.GetHasQuarterState());
            return ("You inserted a quarter");
        }

        public string EjectQuarter() {
            return "You haven't inserted a quarter\n";
        }

        public string TurnCrank() {
            return "You turned but there's no quarter\n";
        }

        public string Dispense() {
            return "You need to pay first\n";
        }

        public override string ToString() {
            return "State: NoQuarter.\n Waiting for quarter\n";
        }

        public string Refill(int i) {
            gumballMachine.Count += i;
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "filled her up";
        }
    }

    public class HasQuarterState : IState {
        GumballMachine gumballMachine;
        Random randomWinner = new Random();

        public HasQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "You can't insert another quarter\n";
        }

        public string EjectQuarter() {
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "Quarter returned\n";
        }

        public string TurnCrank() {
            string output;
            output = "You turned...\n";

            //int winner = randomWinner.Next(10);
            //if (winner == 0 && gumballMachine.Count > 1) {
            if (gumballMachine.Count == 10) {
                gumballMachine.SetState(gumballMachine.GetWinnerState());
            }
            else {
                gumballMachine.SetState(gumballMachine.GetSoldState());
            }
            return output;
        }

        public string Dispense() {
            string output;

            output = gumballMachine.ReleaseBall();
            output += "No gumball dispensed\n";

            return output;
        }

        public override string ToString() {
            return "State: HasQuarter\n waiting for turn of crank";
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill - there is a quarter in the machine so please turn crank";
        }
    }

    public class SoldState : IState {
        GumballMachine gumballMachine;

        public SoldState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "Please wait, we're already giving you a gumball\n";
        }

        public string EjectQuarter() {
            return "Sorry, you already turned the crank\n";
        }

        public string TurnCrank() {
            return "Turning twice doesn't get you another gumball!\n";
        }

        public string Dispense() {
            string output;
            output = gumballMachine.ReleaseBall();
            if (gumballMachine.Count > 0) {
                gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            }
            else {
                gumballMachine.SetState(gumballMachine.GetSoldOutState());
                output += "Oops, out of gumballs!\n";
            }
            return output;
        }

        public override string ToString() {
            return "State: Sold \n delivering a gumball";
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill - you've turned the crank and I'm about to dispense a gumball";
        }
    }

    public class SoldOutState : IState {
        GumballMachine gumballMachine;

        public SoldOutState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "You can't insert a quarter, the machine is sold out\n";
        }

        public string EjectQuarter() {
            return "You can't eject, you haven't inserted a quarter yet\n";
        }

        public string TurnCrank() {
            return "Sorry, you already turned the crank\n";
        }

        public string Dispense() {
            return "You turned, but there are no gumballs\n";
        }

        public override string ToString() {
            return "State: SoldOut";
        }

        public string Refill(int i) {
            gumballMachine.Count = i;
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "filled her up";
        }
    }

    public class WinnerState : IState {

        GumballMachine gumballMachine;

        public WinnerState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "Please wait, we're already giving you a gumball\n";
        }

        public string EjectQuarter() {
            return "Sorry, you already turned the crank\n";
        }

        public string TurnCrank() {
            return "Turning twice doesn't get you another gumball!\n";
        }

        public string Dispense() {
            string output = "You're a winner.  You get 2 gumballs for your quarter";
            gumballMachine.ReleaseBall();
            if (gumballMachine.Count == 0)
                gumballMachine.SetState(gumballMachine.GetSoldOutState());
            else {
                gumballMachine.ReleaseBall();
                if (gumballMachine.Count == 0)
                    gumballMachine.SetState(gumballMachine.GetSoldOutState());
                else
                    gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            }
            return output;
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill..you've turned the crank and I'm about to dispense 2 gumballs";
        }
    }


    public interface IState {
        string InsertQuarter();
        string EjectQuarter();
        string TurnCrank();
        string Dispense();
        string Refill(int numberOfGumball);
    }

Console app:

static void Main(string[] args) {
            var gumballMachine = new GumballMachine(2);
            while (true) {
                var typeThing = gumballMachine.GetState().GetType();
                //NoQuarter
                if (typeThing == typeof(NoQuarterState)) {
                    Console.WriteLine(gumballMachine.MachineStateHeader());
                    Console.WriteLine("Press 1 to insert quarter or 2 to refill 2 more gumballs");
                    var input = Console.ReadLine();
                    var output = "";
                    if (input == "1")
                        output = gumballMachine.InsertQuarter();
                    if (input == "2")
                        output = gumballMachine.Refill(2);
                    Console.WriteLine(output);
                }

                //HasQuarter
                if (typeThing == typeof(HasQuarterState)) {
                    Console.WriteLine(gumballMachine.MachineStateHeader());
                    Console.WriteLine("Press 2 to turn crank or 3 to eject quarter");
                    var input = Console.ReadLine();
                    var output = "";
                    if (input == "2")
                        output = gumballMachine.TurnCrank();
                    if (input == "3")
                        output = gumballMachine.EjectQuarter();
                    Console.WriteLine(output);
                }
                
                //SoldOut
                if (typeThing == typeof(SoldOutState)) {
                    Console.WriteLine(gumballMachine.MachineStateHeader());
                    Console.WriteLine("Press 4 to refill 4 gumballs, 5 to refill 5 gumballs");
                    var input = Console.ReadLine();
                    var output = "";
                    int i = 0;
                    Int32.TryParse(input, out i);
                    if (input == "4" || input == "5")
                        output = gumballMachine.Refill(i);
                    Console.WriteLine(output);
                }
            }
        }

tests:

[TestFixture]
    public class GumballTests {
        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_0_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(0);
            Assert.AreEqual(0, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
        }

        [Test]
        public void machine_is_in_has_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter() {
            var gumballMachine = new GumballMachine(5);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_ejects() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            gumballMachine.EjectQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
            Assert.AreEqual(4, gumballMachine.Count);
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_1_gumball_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(1);
            Assert.AreEqual(1, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }

        [Test]
        public void machine_gives_correct_message_when_sold_out_and_user_trys_to_insert_a_quarter() {
            var gumballMachine = new GumballMachine(0);
            var output = gumballMachine.InsertQuarter();
            Assert.AreEqual("You can't insert a quarter, the machine is sold out\n", output);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }

        [Test]
        public void machine_gives_2_gumballs_when_number_in_machine_is_10_faking_a_winner_random_scenario() {
            var gumballMachine = new GumballMachine(10);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            var output = gumballMachine.TurnCrank();
            StringAssert.Contains("You're a winner", output);
            Assert.AreEqual(8, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_goes_to_correct_number_of_gumballs_when_refill_is_done_at_sold_out_state() {
            var gumballMachine = new GumballMachine(0);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            var output = gumballMachine.Refill(15);
            Assert.AreEqual(15, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_goes_to_correct_number_of_gumballs_when_refill_is_done_on_no_quarter_state() {
            var gumballMachine = new GumballMachine(5);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
            var output = gumballMachine.Refill(15);
            Assert.AreEqual(20, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }


        [Test]
        public void TestGumballMachine() {
            GumballMachine gumballMachine = new GumballMachine(5);
            StringBuilder gumballMachineOutput = new StringBuilder();

            gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank());
            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.Refill(5) + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");



            //Because of the System.Random object, there is no way to know
            //the outcome of the turn of the crank. Therefore, I am writing
            //to the console. Use the Console.Out tab of NUnit
            Console.WriteLine(gumballMachineOutput.ToString());
        }
    }
| | # 

From Ch10 of Head First Design Patterns.

Problem:  I have a WindowsCE device which every now and again gets into an unknown state due to connetions lost/something strange happening in the field.

Solution:  Implement a state machine pattern to make sure these cases are handled correctly

http://stackoverflow.com/questions/8264314/windows-forms-simple-state-machine

namespace GumballState {
    class Program {
        static void Main(string[] args) {
            new GumballMachine();           
        }
    }

    enum StateType {
        SOLD_OUT = 0,
        NO_QUARTER = 1,
        HAS_QUARTER = 2,
        SOLD = 3    
    }

    class GumballMachine {
        //created an instance variable to hold the state values
        private int state = (int)StateType.SOLD_OUT;

        public GumballMachine() {
            InsertQuarter();
        }

        void InsertQuarter() {
            //conditional code within method to handle each state
            if (state == (int)StateType.HAS_QUARTER)
                Console.WriteLine("You can't insert another quarter");
            if (state == (int)StateType.SOLD_OUT)
                Console.WriteLine("You can't insert a quarter, the machine is sold out");
            if (state == (int)StateType.SOLD)
                Console.WriteLine("Please wait, we're giving you a gumball");
            if (state == (int)StateType.NO_QUARTER) {
                state = (int)StateType.HAS_QUARTER;
                Console.WriteLine("You inserterd a quarter");
            }
        }
    }
}

felt a bit verbose for a simple example.. so using static readonly ints…maybe better private const int  (then CAPS would be more ok!)

namespace GumballState {
    class Program {
        static void Main(string[] args) {
            new GumballMachine();           
        }
    }

    class GumballMachine {
        static readonly int SOLD_OUT = 0;
        static readonly int NO_QUARTER = 1;
        static readonly int HAS_QUARTER = 2;
        static readonly int SOLD = 3;

        //created an instance variable to hold the state values
        int state = SOLD_OUT;

        public GumballMachine() {
            InsertQuarter();
        }

        void InsertQuarter() {
            //conditional code within method to handle each state
            if (state == HAS_QUARTER)
                Console.WriteLine("You can't insert another quarter");
            if (state == SOLD_OUT)
                Console.WriteLine("You can't insert a quarter, the machine is sold out");
            if (state == SOLD)
                Console.WriteLine("Please wait, we're giving you a gumball");
            if (state == NO_QUARTER) {
                state = HAS_QUARTER;
                Console.WriteLine("You inserterd a quarter");
            }
        }
    }
}

this is fine

class Program {
        static void Main(string[] args) {
            new GumballMachine(20);           
        }
    }

    public class GumballMachine {
        //enums is bigger app.. usually CamelCase
        static readonly int SOLD_OUT = 0;
        static readonly int NO_QUARTER = 1;
        static readonly int HAS_QUARTER = 2;
        static readonly int SOLD = 3;

        //created an instance variable to hold the state value... could use underscore here.
        public int state = SOLD_OUT;
        //another instance variable to keep track of number of gumballs in machine
        public int currentNumberOfGumballsInMachine = 0;

        public GumballMachine(int initialNumberOfGumballsInMachine) {
            currentNumberOfGumballsInMachine = initialNumberOfGumballsInMachine;
            if (currentNumberOfGumballsInMachine > 0)
                state = NO_QUARTER;
        }

        public string DisplayStatus() {
            var x = "Number of Gumballs: " + currentNumberOfGumballsInMachine.ToString();
            x += Environment.NewLine;
            x += "State: " + state.ToString();
            x += Environment.NewLine;
            return x;
        }

        public void InsertQuarter() {
            //conditional code within method to handle each state
            if (state == HAS_QUARTER)
                Console.WriteLine("You can't insert another quarter");
            if (state == SOLD_OUT)
                Console.WriteLine("You can't insert a quarter, the machine is sold out");
            if (state == SOLD)
                Console.WriteLine("Please wait, we're giving you a gumball");
            if (state == NO_QUARTER) {
                state = HAS_QUARTER;
                Console.WriteLine("You inserterd a quarter");
            }
        }

        public void EjectQuarter() {
            if (state == HAS_QUARTER) {
                Console.WriteLine("Quarter returned");
                state = NO_QUARTER;
            } else
                Console.WriteLine("logic error in EjectQuarter");
        }

        public void TurnCrank() {
            if (state == HAS_QUARTER) {
                Console.WriteLine("You turned");
                state = SOLD;
                Dispense();
            }
        }

        public void Dispense() {
            if (state == SOLD) {
                Console.WriteLine("a gumball comes rolling out of the slot");
                currentNumberOfGumballsInMachine -= 1;
                if (currentNumberOfGumballsInMachine == 0) {
                    Console.WriteLine("Out of gumballs");
                    state = SOLD_OUT;
                }
                else
                    state = NO_QUARTER;
            }
        }
    }

and wrapping some smelly testing around it:

[TestFixture]
    public class GumballTests {
        [Test]
        public void MyTestMethod() {
            var g = new GumballMachine(3);
            var y = g.DisplayStatus();
            Console.WriteLine(y);

            g.InsertQuarter();
            g.TurnCrank();
            y = g.DisplayStatus();
            Console.WriteLine(y);


            //Assert.AreEqual(3, g.currentNumberOfGumballsInMachine);
        }
    }

not refactored at all.. but goal is to learn about state…

What happens if code changes ie a new feature request – State Pattern

Problem is that now I need to change a lot of my state code.. gets messy and complex very quickly.

So we want something down the road which is easy to maintain.

Each state class is responsible for the behaviour of the ‘gumball machine’ when it is in that state

public class GumballMachine {
        IState soldOutState;
        IState noQuarterState;
        IState hasQuarterState;
        IState soldState;

        IState state;

        int count = 0;

        public int Count { get { return count; } }

        public GumballMachine(int numberGumballs) {
            //creating the state instances - one of each
            noQuarterState = new NoQuarterState(this);
            hasQuarterState = new HasQuarterState(this);
            soldState = new SoldState(this);
            soldOutState = new SoldOutState(this);
            this.count = numberGumballs;
            if (numberGumballs > 0)
                state = noQuarterState;
            else
                state = soldOutState;
        }

        public string InsertQuarter() {
            return state.InsertQuarter();
        }

        public string EjectQuarter() {
            return state.EjectQuarter();
        }

        public string TurnCrank() {
            return state.TurnCrank() + state.Dispense();
        }

        public void SetState(IState state) {
            this.state = state;
        }

        public IState GetState() {
            return state;
        }

        public IState GetNoQuarterState() {
            return noQuarterState;
        }

        public IState GetHasQuarterState() {
            return hasQuarterState;
        }

        public IState GetSoldState() {
            return soldState;
        }

        public IState GetSoldOutState() {
            return soldOutState;
        }

        public string ReleaseBall() {
            if (count != 0)
                count--;
            return ("A gumball comes rolling out the slot...\n\n");
        }

        public string MachineStateHeader() {
            var result = new StringBuilder();
            result.Append("Mighty Gumball, Inc.");
            result.Append("\nC# Enabled Standing Gumball Model #2005\n");
            result.Append("Inventory: " + count + " gumball");
            if (count != 1) {
                result.Append("s");
            }
            result.Append("\nMachine is " + state.ToString());

            return result.ToString();
        }
    }

   
    public class NoQuarterState : IState {
        //a reference to the gumballMachine
        GumballMachine gumballMachine;

        public NoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            gumballMachine.SetState(gumballMachine.GetHasQuarterState());
            return ("You inserted a quarter");
        }

        public string EjectQuarter() {
            return "You haven't inserted a quarter\n";
        }

        public string TurnCrank() {
            return "You turned but there's no quarter\n";
        }

        public string Dispense() {
            return "You need to pay first\n";
        }

        public override string ToString() {
            return "State: NoQuarter.\n Waiting for quarter\n";
        }
    }

    public class HasQuarterState : IState {
        GumballMachine gumballMachine;
        //IState soldState;
        //Random randomWinner = new Random(System.DateTime.Now.Millisecond);

        public HasQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
            //soldState = new SoldState(gumballMachine);
        }

        public string InsertQuarter() {
            return "You can't insert another quarter\n";
        }

        public string EjectQuarter() {
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "Quarter returned\n";
        }

        public string TurnCrank() {
            string output;
            output = "You turned...\n";

            //int winner = randomWinner.Next(10);
            //if (winner == 0 && gumballMachine.Count > 1) {
            //    gumballMachine.StateOfMachine = new WinnerState(gumballMachine);
            //}
            //else {
            gumballMachine.SetState(gumballMachine.GetSoldState());
            //}

            return output;
        }

        public string Dispense() {
            string output;

            output = gumballMachine.ReleaseBall();
            output += "No gumball dispensed\n";

            return output;
        }

        public override string ToString() {
            return "State: HasQuarter\n waiting for turn of crank";
        }
    }

    public class SoldState : IState {
        GumballMachine gumballMachine;

        public SoldState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "Please wait, we're already giving you a gumball\n";
        }

        public string EjectQuarter() {
            return "Sorry, you already turned the crank\n";
        }

        public string TurnCrank() {
            return "Turning twice doesn't get you another gumball!\n";
        }

        public string Dispense() {
            string output;
            output = gumballMachine.ReleaseBall();
            if (gumballMachine.Count > 0) {
                gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            }
            else {
                gumballMachine.SetState(gumballMachine.GetSoldOutState());
                output += "Oops, out of gumballs!\n";
            }
            return output;
        }

        public override string ToString() {
            return "State: Sold \n delivering a gumball";
        }
    }

    public class SoldOutState : IState {
        GumballMachine gumballMachine;

        public SoldOutState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "You can't insert a quarter, the machine is sold out\n";
        }

        public string EjectQuarter() {
            return "You can't eject, you haven't inserted a quarter yet\n";
        }

        public string TurnCrank() {
            return "Sorry, you already turned the crank\n";
        }

        public string Dispense() {
            string output;

            output = gumballMachine.ReleaseBall();
            output += "You turned, but there are no gumballs\n";

            return output;
        }

        public override string ToString() {
            return "State: SoldOut";
        }
    }


    public interface IState {
        string InsertQuarter();
        string EjectQuarter();
        string TurnCrank();
        string Dispense();
    }

and tests:

[TestFixture]
    public class GumballTests {
        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_0_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(0);
            Assert.AreEqual(0, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
        }

        [Test]
        public void machine_is_in_has_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter() {
            var gumballMachine = new GumballMachine(5);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_ejects() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            gumballMachine.EjectQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
            Assert.AreEqual(4, gumballMachine.Count);
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_1_gumball_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(1);
            Assert.AreEqual(1, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }


        [Test]
        public void machine_gives_correct_message_when_sold_out_and_user_trys_to_insert_a_quarter() {
            var gumballMachine = new GumballMachine(0);
            var output = gumballMachine.InsertQuarter();
            Assert.AreEqual("You can't insert a quarter, the machine is sold out\n", output);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }


        [Test]
        public void TestGumballMachine() {
            GumballMachine gumballMachine = new GumballMachine(5);
            StringBuilder gumballMachineOutput = new StringBuilder();

            gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank());
            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.Refill(5) + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");



            //Because of the System.Random object, there is no way to know
            //the outcome of the turn of the crank. Therefore, I am writing
            //to the console. Use the Console.Out tab of NUnit
            Console.WriteLine(gumballMachineOutput.ToString());
        }
    }

Added in a Winner State, and a refill transition/action.

public class GumballMachine {
        IState soldOutState;
        IState noQuarterState;
        IState hasQuarterState;
        IState soldState;
        IState winnerState;

        IState state;

        int count = 0;

        public int Count { get { return count; } set { count = value; } }

        public GumballMachine(int numberGumballs) {
            //creating the state instances - one of each
            noQuarterState = new NoQuarterState(this);
            hasQuarterState = new HasQuarterState(this);
            soldState = new SoldState(this);
            soldOutState = new SoldOutState(this);
            winnerState = new WinnerState(this);
            this.count = numberGumballs;
            if (numberGumballs > 0)
                state = noQuarterState;
            else
                state = soldOutState;
        }

        public string InsertQuarter() {
            return state.InsertQuarter();
        }

        public string EjectQuarter() {
            return state.EjectQuarter();
        }

        public string TurnCrank() {
            var output = state.TurnCrank();
            output += state.Dispense();
            return output;
        }

        public string Refill(int i) {
            return state.Refill(i);
        }

        public void SetState(IState state) {
            this.state = state;
        }

        public IState GetState() {
            return state;
        }

        public IState GetNoQuarterState() {
            return noQuarterState;
        }

        public IState GetHasQuarterState() {
            return hasQuarterState;
        }

        public IState GetSoldState() {
            return soldState;
        }

        public IState GetSoldOutState() {
            return soldOutState;
        }

        public IState GetWinnerState() {
            return winnerState;
        }

        public string ReleaseBall() {
            if (count != 0)
                count--;
            return ("A gumball comes rolling out the slot...\n\n");
        }

        public string MachineStateHeader() {
            var result = new StringBuilder();
            result.Append("Mighty Gumball, Inc.");
            result.Append("\nC# Enabled Standing Gumball Model #2005\n");
            result.Append("Inventory: " + count + " gumball");
            if (count != 1) {
                result.Append("s");
            }
            result.Append("\nMachine is " + state.ToString());

            return result.ToString();
        }
    }

    public class NoQuarterState : IState {
        //a reference to the gumballMachine
        GumballMachine gumballMachine;

        public NoQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            gumballMachine.SetState(gumballMachine.GetHasQuarterState());
            return ("You inserted a quarter");
        }

        public string EjectQuarter() {
            return "You haven't inserted a quarter\n";
        }

        public string TurnCrank() {
            return "You turned but there's no quarter\n";
        }

        public string Dispense() {
            return "You need to pay first\n";
        }

        public override string ToString() {
            return "State: NoQuarter.\n Waiting for quarter\n";
        }

        public string Refill(int i) {
            gumballMachine.Count += i;
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "filled her up";
        }
    }

    public class HasQuarterState : IState {
        GumballMachine gumballMachine;
        Random randomWinner = new Random();

        public HasQuarterState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "You can't insert another quarter\n";
        }

        public string EjectQuarter() {
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "Quarter returned\n";
        }

        public string TurnCrank() {
            string output;
            output = "You turned...\n";

            //int winner = randomWinner.Next(10);
            //if (winner == 0 && gumballMachine.Count > 1) {
            if (gumballMachine.Count == 10) {
                gumballMachine.SetState(gumballMachine.GetWinnerState());
            }
            else {
                gumballMachine.SetState(gumballMachine.GetSoldState());
            }
            return output;
        }

        public string Dispense() {
            string output;

            output = gumballMachine.ReleaseBall();
            output += "No gumball dispensed\n";

            return output;
        }

        public override string ToString() {
            return "State: HasQuarter\n waiting for turn of crank";
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill - there is a quarter in the machine so please turn crank";
        }
    }

    public class SoldState : IState {
        GumballMachine gumballMachine;

        public SoldState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "Please wait, we're already giving you a gumball\n";
        }

        public string EjectQuarter() {
            return "Sorry, you already turned the crank\n";
        }

        public string TurnCrank() {
            return "Turning twice doesn't get you another gumball!\n";
        }

        public string Dispense() {
            string output;
            output = gumballMachine.ReleaseBall();
            if (gumballMachine.Count > 0) {
                gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            }
            else {
                gumballMachine.SetState(gumballMachine.GetSoldOutState());
                output += "Oops, out of gumballs!\n";
            }
            return output;
        }

        public override string ToString() {
            return "State: Sold \n delivering a gumball";
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill - you've turned the crank and I'm about to dispense a gumball";
        }
    }

    public class SoldOutState : IState {
        GumballMachine gumballMachine;

        public SoldOutState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "You can't insert a quarter, the machine is sold out\n";
        }

        public string EjectQuarter() {
            return "You can't eject, you haven't inserted a quarter yet\n";
        }

        public string TurnCrank() {
            return "Sorry, you already turned the crank\n";
        }

        public string Dispense() {
            string output;

            output = gumballMachine.ReleaseBall();
            output += "You turned, but there are no gumballs\n";

            return output;
        }

        public override string ToString() {
            return "State: SoldOut";
        }

        public string Refill(int i) {
            gumballMachine.Count = i;
            gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            return "filled her up";
        }
    }

    public class WinnerState : IState {

        GumballMachine gumballMachine;

        public WinnerState(GumballMachine gumballMachine) {
            this.gumballMachine = gumballMachine;
        }

        public string InsertQuarter() {
            return "Please wait, we're already giving you a gumball\n";
        }

        public string EjectQuarter() {
            return "Sorry, you already turned the crank\n";
        }

        public string TurnCrank() {
            return "Turning twice doesn't get you another gumball!\n";
        }

        public string Dispense() {
            string output = "You're a winner.  You get 2 gumballs for your quarter";
            gumballMachine.ReleaseBall();
            if (gumballMachine.Count == 0)
                gumballMachine.SetState(gumballMachine.GetSoldOutState());
            else {
                gumballMachine.ReleaseBall();
                if (gumballMachine.Count == 0)
                    gumballMachine.SetState(gumballMachine.GetSoldOutState());
                else
                    gumballMachine.SetState(gumballMachine.GetNoQuarterState());
            }
            return output;
        }

        public string Refill(int numberOfGumball) {
            return "Can't refill..you've turned the crank and I'm about to dispense 2 gumballs";
        }
    }


    public interface IState {
        string InsertQuarter();
        string EjectQuarter();
        string TurnCrank();
        string Dispense();
        string Refill(int numberOfGumball);
    }

and tests:

  [TestFixture]
    public class GumballTests {
        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_0_gumballs_to_start_with() {
            var gumballMachine = new GumballMachine(0);
            Assert.AreEqual(0, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
        }

        [Test]
        public void machine_is_in_has_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter() {
            var gumballMachine = new GumballMachine(5);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_ejects() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            gumballMachine.EjectQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_is_in_no_quarter_state_if_has_5_gumballs_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(5);
            Assert.AreEqual(5, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
            Assert.AreEqual(4, gumballMachine.Count);
        }

        [Test]
        public void machine_is_in_sold_out_state_if_has_1_gumball_to_start_with_and_person_inserts_quarter_then_turns_crank() {
            var gumballMachine = new GumballMachine(1);
            Assert.AreEqual(1, gumballMachine.Count);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            //this actually turns crank and dispenses
            gumballMachine.TurnCrank();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }

        [Test]
        public void machine_gives_correct_message_when_sold_out_and_user_trys_to_insert_a_quarter() {
            var gumballMachine = new GumballMachine(0);
            var output = gumballMachine.InsertQuarter();
            Assert.AreEqual("You can't insert a quarter, the machine is sold out\n", output);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            Assert.AreEqual(0, gumballMachine.Count);
        }

        [Test]
        public void machine_gives_2_gumballs_when_number_in_machine_is_10_faking_a_winner_random_scenario() {
            var gumballMachine = new GumballMachine(10);
            gumballMachine.InsertQuarter();
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(HasQuarterState)));
            var output = gumballMachine.TurnCrank();
            StringAssert.Contains("You're a winner", output);
            Assert.AreEqual(8, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_goes_to_correct_number_of_gumballs_when_refill_is_done_at_sold_out_state() {
            var gumballMachine = new GumballMachine(0);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(SoldOutState)));
            var output = gumballMachine.Refill(15);
            Assert.AreEqual(15, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }

        [Test]
        public void machine_goes_to_correct_number_of_gumballs_when_refill_is_done_on_no_quarter_state() {
            var gumballMachine = new GumballMachine(5);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
            var output = gumballMachine.Refill(15);
            Assert.AreEqual(20, gumballMachine.Count);
            Assert.That(gumballMachine.GetState(), Is.TypeOf(typeof(NoQuarterState)));
        }


        [Test]
        public void TestGumballMachine() {
            GumballMachine gumballMachine = new GumballMachine(5);
            StringBuilder gumballMachineOutput = new StringBuilder();

            gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank());
            //gumballMachineOutput.Append(gumballMachine.InsertQuarter());
            //gumballMachineOutput.Append(gumballMachine.TurnCrank() + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");

            //gumballMachineOutput.Append(gumballMachine.Refill(5) + "\n");

            //gumballMachineOutput.Append(gumballMachine.MachineStateHeader() + "\n");



            //Because of the System.Random object, there is no way to know
            //the outcome of the turn of the crank. Therefore, I am writing
            //to the console. Use the Console.Out tab of NUnit
            Console.WriteLine(gumballMachineOutput.ToString());
        }
    }

| | #