Glimpse / Glimpse.Prototype

Glimpse v2 prototype
MIT License
185 stars 42 forks source link

Create abstraction for Discoverable/Fixed Providers #32

Closed avanderhoorn closed 9 years ago

avanderhoorn commented 9 years ago

Currently for every new extension point we have to create a new Discoverable/Fixed Provider Class as well as an accompanying interface. Every implementation is the same and we could make life simpler by abstracting out the implementation and using generics.

Current Impementation

Fixed Provider

public class FixedInspectorStartupProvider : IInspectorStartupProvider
{
    public FixedInspectorStartupProvider()
        : this(Enumerable.Empty<IInspectorStartup>())
    {
    }

    public FixedInspectorStartupProvider(IEnumerable<IInspectorStartup> controllerTypes)
    {
        Profilers = new List<IInspectorStartup>(controllerTypes);
    }

    public IList<IInspectorStartup> Profilers { get; }

    IEnumerable<IInspectorStartup> IInspectorStartupProvider.Startups => Profilers;
}

Discoverable Provider

public class DefaultInspectorStartupProvider : IInspectorStartupProvider
{
    private readonly ITypeService _typeService;

    public DefaultInspectorStartupProvider(ITypeService typeService)
    {
        _typeService = typeService;
    }

    public IEnumerable<IInspectorStartup> Startups
    {
        get { return _typeService.Resolve<IInspectorStartup>().ToArray(); }
    }
}

Provider Interface

public interface IInspectorStartupProvider
{
    IEnumerable<IInspectorStartup> Startups { get; }
}

Provider Registration

public static IServiceCollection GetDefaultServices()
{
    var services = new ServiceCollection();

    ...
    services.AddSingleton<IInspectorStartupProvider, DefaultInspectorStartupProvider>();
    ...

    return services;
}

Provider Injection

public class SomeClass
{
    public SomeClass(IInspectorStartupProvider inspectorStartupProvider)
    {
        ...
    }
}

Problem

The above pattern needs to be repeated for every provider. By providing an implementation based on a common class and generics, we can get away from needing to repeat this pattern every time we need a provider. By switching over to this, we would be able to switch over the above implementation for at least 7 different sets of providers, saving 14 classes and 7 interfaces.

New Proposal

Fixed Provider

public class FixedExtensionProvider<T> : IExtensionProviderr<T>
{
    public FixedExtensionProvider()
        : this(Enumerable.Empty<T>())
    {
    }

    public FixedExtensionProvider(IEnumerable<T> extensionTypes)
    {
        Profilers = new List<T>(extensionTypes);
    }

    public IList<T> Instances { get; }

    IEnumerable<T> IExtensionProvider.Instances => Instances;
}

Discoverable Provider

public class DefaultExtensionProviderr<T> : IExtensionProviderr<T>
{
    private readonly ITypeService _typeService;

    public DefaultInspectorStartupProvider(ITypeService typeService)
    {
        _typeService = typeService;
    }

    public IEnumerable<T> Instances
    {
        get { return _typeService.Resolve<T>().ToArray(); }
    }
}

Provider Interface

public interface IExtensionProvider<T>
{
    IEnumerable<T> Instances { get; }
}

Provider Registration

public static IServiceCollection GetDefaultServices()
{
    var services = new ServiceCollection();

    ...
    services.AddSingleton<IExtensionProvider<IInspectorStartup>, DefaultExtensionProvider<IInspectorStartup>>();
    ...

    return services;
}

Provider Injection

public class SomeClass
{
    public SomeClass(IExtensionProvider<IInspectorStartup> inspectorStartupProvider)
    {
        ...
    }
}