嵌套装饰对象,中间有一个工厂

Nested Decoratee with a Factory in between

我们有一个由 3 个 decoratee 组成的层次结构,实现了如下接口:

public interface IRetrieve
{
    List<Widget> Retrieve(List<long> ids);
}

我们正在尝试使用以下模式:

运行时代码如下所示:

RetrieveBatcher(装饰器)

class RetrieveBatcher : IRetriever
{
    Func<IRetriever> _decoratee;

    public RetrieveBatcher(Func<IRetriever> decoratee)
    {
        _decoratee = decoratee;
    }

    public List<Widget> Retrieve(List<long> ids) {
        return ids
           .Batch(10)
           .AsParallel()
           .SelectMany(b => _decoratee().Retrieve(b))
           .ToList();    
    }
}

RetrieveTimer(装饰器)

class RetrieveTimer : IRetriever
{
    private readonly IRetriever _retriever;
    private const int timeout = 5;

    public class RetrieveTimer(IRetriever retriever) : IRetriever
    {
        // This needs to be the "core" retriever
        _retriever = retriever;
    }

    public List<Widget> Retrieve(List<long> ids) {
        var task = Task.Run(() => 
            {
                return _retriever.Retrieve(ids);
            }
        );
        if (task.Wait(TimeSpan.FromSeconds(timeout)))
        {
            return task.Result;
        }
        else
        {
            // handle "timer exceeded" fallout
            throw new Exception("timer exceeded");
        }
    }
}

RetrieveCore

class RetrieveCore : IRetriever {
    public List<Widget> Retrieve(List<long> ids) 
    {
        // Do something
        return new List<Widget>();
    }    
}

我正在努力注册,因为这不是一个简单的装饰器层次结构。相反,我们有:

我们不得不 "cheat" 使用 SimpleInjector,按照:

// outermost layer:
container.Register<IRetriever, RetrieveBatcher>();

// Function (Factory) that returns "Timed" utility
// See: http://simpleinjector.readthedocs.io/en/latest/howto.html#register-factory-delegates
// This registers the Func<> as the singleton, not the RetrieveTimer instance
container.RegisterSingleton<Func<IRetriever>>(
    () => new RetrieveTimer(new RetrieveCore()));

这可行,但实际的 "new RetrieveCore()" 依赖性似乎不太理想。

有没有什么方法可以配置 SimpleInjector 来正确处理这种情况?

我看不出为什么常规 RegisterDecorator 电话无法解决您的问题:

container.Register<IRetriever, RetrieveCore>();
container.RegisterDecorator<IRetriever, RetrieveTimer>();
container.RegisterDecorator<IRetriever, RetrieveBatcher>();

解析 IRetriever 后会产生以下对象图:

new RetrieveBatcher(() => new RetrieveTimer(new RetrieveCore()));