Design Patterns

Last Updated: 9/25/2024

Iterator

  • Provides a way to access the elements of an object sequentially without exposing its underlying representation/data structure.

Classical Structure

Iterator Classical Structure

Scenario

  • Build a browser which store history

Problem

public class BrowseHistory
{
    private List<string> urls = new List<string>();

    public List<string> Urls { get => urls; }

    public void Push(string url)
    {
        urls.Add(url);
    }

    public string Pop() 
    { 
        var lastIndex = urls.Count - 1;
        var lastUrl = urls[lastIndex];
        urls.RemoveAt(lastIndex);
        return lastUrl;
    }

}
  • If the history class uses different data structure to store URLs, the main class will break.
  • Every time we change the internals of the object, you end up with breaking changes
  • Changing the internal of an object shouldn't affect it consumers

Solution

public interface IIterator
{
    bool HasNext();
    string Current();
    void Next();
}
public class BrowseHistory
{
    private List<string> urls = new List<string>();

    public void Push(string url)
    {
        urls.Add(url);
    }

    public string Pop()
    {
        var lastIndex = urls.Count - 1;
        var lastUrl = urls[lastIndex];
        urls.RemoveAt(lastIndex);
        return lastUrl;
    }

    public IIterator CreateIterator()
    {
        return new ListIterator(this);
    }


    public class ListIterator : IIterator
    {
        private readonly BrowseHistory history;
        private int index;

        public ListIterator(BrowseHistory history)
        {
            this.history = history;
        }
        public string Current()
        {
            return history.urls[index];
        }

        public bool HasNext()
        {
            return index < history.urls.Count;
        }

        public void Next()
        {
            index++;
        }
    }
}
public class Program
{
    static void Main(string[] args)
    {
        var browseHistory = new BrowseHistory();
        browseHistory.Push("a");
        browseHistory.Push("b");
        browseHistory.Push("c");

        var iterator = browseHistory.CreateIterator();
        while (iterator.HasNext())
        {
            var url = iterator.Current();
            Console.WriteLine(url);
            iterator.Next();
        }
    }
}

Example Structure

Iterator Example Structure

Example Code