问题
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