Factory with Autofac dependencies

感情迁移 提交于 2019-12-24 03:20:24

问题


I want to write a factory for creating various types of "xxNotification" classes. My concrete "xxNotification" has dependencies registered with AutoFac. I would like to get/resolve instance of "xxNotification" using Autofac. How to do that?

public interface INotification
{
    void Notify(string Action, int OrderID);
}

public class MagentoOrderStateNotification : INotification
{
    private readonly GenericRepository<Order> _orderRepository;
    private readonly OMRestIntegrationService _oMRestIntegrationService;

    public MagentoOrderStateNotification(GenericRepository<Order> orderRepository, OMRestIntegrationService oMRestIntegrationService)
    {
        _orderRepository = orderRepository;
        _oMRestIntegrationService = oMRestIntegrationService;
    }

    public void Notify(string Action, int OrderID)
    {
        //implementation...
    }
}

public class NotificationFactory
{
    public INotification GetNotification(string NotificationName)
    {
        switch (NotificationName)
        {
            case "MagentoOrderStateNotification":
                //resolve instance of MagentoOrderStateNotification
        }
    }
}

回答1:


This looks like a good candidate for the Strategy Pattern.

Interfaces

public interface INotification
{
    void Notify(string Action, int OrderID);
    bool AppliesTo(string NotificationName);
}

public interface INotificationStrategy
{
    void Notify(string NotificationName, string Action, int OrderID);
}

INotification Implementations

public class MagentoOrderStateNotification : INotification
{
    private readonly GenericRepository<Order> _orderRepository;
    private readonly OMRestIntegrationService _oMRestIntegrationService;

    public MagentoOrderStateNotification(GenericRepository<Order> orderRepository, OMRestIntegrationService oMRestIntegrationService)
    {
        _orderRepository = orderRepository;
        _oMRestIntegrationService = oMRestIntegrationService;
    }

    public void Notify(string Action, int OrderID)
    {
        //implementation...
    }

    public bool AppliesTo(string NotificationName)
    {
        // Note that you can make the criteria to use this
        // service as advanced as you need to. You could even
        // design your strategy to use multiple services in specific
        // scenarios. But putting that logic here has many advantages
        // over a switch case statement.
        return NotificationName == "a";
    }
}

public class FooOrderStateNotification : INotification
{
    public void Notify(string Action, int OrderID)
    {
        //implementation...
    }

    public bool AppliesTo(string NotificationName)
    {
        return NotificationName == "b";
    }
}

Strategy

public class NotificationStrategy : INotificationStrategy
{
    private readonly IEnumerable<INotification> oNotifications;

    public MessageStrategy(IEnumerable<INotification> oNotifications)
    {
        if (oNotifications == null)
            throw new ArgumentNullException("oNotifications");
        this.oNotifications = oNotifications;
    }

    public void Notify(string NotificationName, string Action, int OrderID)
    {
        var notification = this.oNotifications
            .FirstOrDefault(x => x.AppliesTo(NotificationName));

        // Possible alternative: get multiple implementations and
        // then loop through them, executing each one.
        // var notifications = this.oNotifications
        //     .Where(x => x.AppliesTo(NotificationName)).ToArray();

        if (notification == null)
        {
            throw new Exception("No notification type registered for " + NotificationName);
        }

        notification.Notify(Action, OrderID);
    }
}

Usage

public class SomeService : ISomeService
{
    private readonly INotificationStrategy oNotificationStrategy;

    public SomeService(INotificationStrategy oNotificationStrategy)
    {
        if (oNotificationStrategy == null)
            throw new ArgumentNullException("oNotificationStrategy");
        this.oNotificationStrategy = oNotificationStrategy;
    }

    public void DoSomething()
    {
        this.oNotificationStrategy.Notify("a", "Hello", 1234);
    }
}

Note that an alternative approach could be to use some "OrderType" state based on the OrderID to lookup the service to use (not sure it actually makes sense to pass OrderID into the Notify() method). But however you slice it this is an application design problem, not a DI problem.

Autofac Registration

There are a few ways you can configure Autofac to register multiple implementations of the same interface for use in the NotificationStrategy constructor. Here are a couple of examples:

Scan

// Note you may need more than one registration if you are spanning
// multiple assemblies.
builder.RegisterAssemblyTypes(typeof(INotification).Assembly)
   .Where(x => typeof(INotification).IsAssignableFrom(x))
   .AsImplementedInterfaces();

When the implementations are registered this way, Autofac will implicitly inject all implementations into any IEnumerable<INotification> constructor parameter.

Cherry Pick

builder.Register<MagentoOrderStateNotification>()
    .Named<INotification>("magentoOrderStateNotification");
builder.Register<FooOrderStateNotification>()
    .Named<INotification>("fooOrderStateNotification");

builder.RegisterType<NotificationStrategy>()
            .As<INotificationStrategy>()
            .WithParameter(
                (p, c) => p.Name == "oNotifications",
                (p, c) => new[]
                    {
                        c.ResolveNamed<INotification>("magentoOrderStateNotification"),
                        c.ResolveNamed<INotification>("fooOrderStateNotification")
                    });


来源:https://stackoverflow.com/questions/46586895/factory-with-autofac-dependencies

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!