2
\$\begingroup\$

In order to grow potatoes I'm implementing the retry pattern. If I fail to grow them, I'd like to try it again later. The first part I've implemented is a collection of delay generators.

Their base type is the DelaySequence:

public abstract class DelaySequence : IEnumerable<TimeSpan>
{
    protected DelaySequence(int count) { Count = count; }

    public int Count { get; }

    public IEnumerator<TimeSpan> GetEnumerator() => Generate().Take(Count).GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    protected abstract IEnumerable<TimeSpan> Generate();
}

I derived three concrete generators from it.

One regular:

public class RegularDelaySequence : DelaySequence
{
    private readonly TimeSpan _delay;
    public RegularDelaySequence(TimeSpan delay, int count) : base(count) { _delay = delay; }
    protected override IEnumerable<TimeSpan> Generate()
    {
        while (true) yield return _delay;
    }
}

and two irregular:

public abstract class IrregularDelaySequence : DelaySequence
{
    protected IrregularDelaySequence(int count) : base(count) { }
}

public class FibonacciDelaySequence : IrregularDelaySequence
{
    private readonly Queue<TimeSpan> _lastPair;
    public FibonacciDelaySequence(TimeSpan firstTwo, TimeSpan firstStep, int count) : base(count)
    {
        _lastPair = new Queue<TimeSpan>(new[]
        {
            firstTwo,
            firstTwo,
            firstTwo + firstStep,
        });
    }
    protected override IEnumerable<TimeSpan> Generate()
    {
        foreach (var delay in _lastPair)
        {
            yield return delay;
        }

        _lastPair.Dequeue();

        while (true)
        {
            var current = _lastPair.Aggregate(TimeSpan.Zero, (sum, next) => sum + next);
            yield return current;
            _lastPair.Enqueue(current);
            _lastPair.Dequeue();
        };
    }
}

public class GeometricDelaySequence : IrregularDelaySequence
{
    private TimeSpan _current;
    private readonly Func<TimeSpan, TimeSpan> _increment;
    public GeometricDelaySequence(TimeSpan first, Func<TimeSpan, TimeSpan> increment, int count) : base(count)
    {
        _current  = first;
        _increment = increment;
    }
    protected override IEnumerable<TimeSpan> Generate()
    {
        yield return _current;

        while (true)
        {
            yield return (_current = _increment(_current));
        };
    }
}

Their usage is very simple. Create an instance, specify the parameters and you're ready to go:

new RegularDelaySequence(TimeSpan.FromSeconds(1), 7).Dump();
new FibonacciDelaySequence(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), 7).Dump();
new GeometricDelaySequence(TimeSpan.FromSeconds(1), ts => ts + ts, 7).Dump();

Dump() is LINQPad's method

Results:

RegularDelaySequence

00:00:01 
00:00:01 
00:00:01 
00:00:01 
00:00:01 
00:00:01 
00:00:01 

FibonacciDelaySequence

00:00:01 
00:00:01 
00:00:04 
00:00:05 
00:00:09 
00:00:14 
00:00:23 

GeometricDelaySequence

00:00:01 
00:00:02 
00:00:04 
00:00:08 
00:00:16 
00:00:32 
00:01:04 
\$\endgroup\$
1
  • 1
    \$\begingroup\$ LOL I got downvoted. Someone doesn't like potatoes ;-) \$\endgroup\$
    – t3chb0t
    Commented Nov 10, 2016 at 12:03

1 Answer 1

2
\$\begingroup\$

IrregularDelaySequence

I don't think the base IrregularDelaySequence class is needed here since it doesn't contain any members. To check if a specified instance is an irregular sequence, you could just compare its type to the RegularDelaySequence. If the type isn't RegularDelaySequence, the sequence is definitly irregular.

FibonacciDelaySequence

The logic of this class isn't quite clear for me.
I'd prefer to use an "oldschool" variables instead of the Queue:

public class FibonacciDelaySequence : DelaySequence
{
    private TimeSpan _prev;
    private TimeSpan _cur;

    public FibonacciDelaySequence(TimeSpan firstTwo, TimeSpan firstStep, int count) : base(count)
    {
        _prev = firstTwo;
        _cur = _prev + firstStep;
    }
    protected override IEnumerable<TimeSpan> Generate()
    {
        yield return _prev;
        yield return _prev;
        yield return _cur;

        while (true)
        {
            var current = _prev + _cur;
            yield return current;
            _prev = _cur;
            _cur = current;
        }
    }
}
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I must admint the oldschool variables look much nicer then my over-engineered queue ;-] \$\endgroup\$
    – t3chb0t
    Commented Nov 10, 2016 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.