I thought that Iterator -- another GoF pattern -- might be a good example of something that encapsulates state switching logic in some cases, when the states are switched strictly in the order you know beforehand. I realize that not every State implementation is that simple, but if yours is, you might want to use the idea: just pass the IEnumerable of IState to the implementation of State, and use MoveNext() and Current {get;} on the Enumerator internally to switch states. If you are doing something like this, it might be a good idea to jump back to State #1 after you've reached State #Last. I've written a little helper class to do just that:
using System;
using System.Collections.Generic;
namespace Primitives
{
    public class CycledEnumerator<T> : IEnumerator<T>
        where T : class
    {
        private LinkedList<T> _chainedObjects;
        private LinkedListNode<T> _currentObject;
        public CycledEnumerator(IEnumerable<T> objectsToChain)
        {
            if (objectsToChain == null)
            {
                throw new ArgumentNullException("objectsToChain");
            }
            _chainedObjects = new LinkedList<T>(objectsToChain);
            if (_chainedObjects.Contains(null))
            {
                throw new ArgumentException("Nulls are not allowed.", "objectsToChain");
            }
            if (_chainedObjects.Count < 1)
            {
                throw new ArgumentException("Need at least one item in the set.", "objectsToChain");
            }
            this.MoveBeforeFirstElement();
        }
        private void MoveBeforeFirstElement()
        {
            _currentObject = null; // I don't like nulls at all, but I'm putting it here for the sake of consistency with Microsoft's implementations of Enumerator (which is a variant of GoF Iterator pattern).
        }
        public T Current
        {
            get
            {
                return _currentObject.Value;
            }
        }
        public void Dispose()
        {
        }
        object System.Collections.IEnumerator.Current
        {
            get
            {
                return _currentObject;
            }
        }
        public bool MoveNext()
        {
            if ((_currentObject == null) || (_currentObject.Next == null))
            {
                MoveToFirstElement();
            }
            else
            {
                _currentObject = _currentObject.Next;
            }
            return true;
        }
        private void MoveToFirstElement()
        {
            _currentObject = _chainedObjects.First;
        }
        public void Reset()
        {
            this.MoveBeforeFirstElement();
        }
    }
}
(That said, I don't like Iterator much (and all of its buddies, like the Enumerator): it exposes too much of its state to the client, and has too complex a contract. It's all like "if MoveNext() returns true, then Current contains the next element", or: "after initialization the Enumerator is positioned before the first element, and you should call MoveNext() to get anything from it".)
 
No comments:
Post a Comment