C# 依赖项注入类型选择

C# 依赖项注入类型选择,c#,dependency-injection,architecture,C#,Dependency Injection,Architecture,最近我遇到了一个问题,我必须根据参数选择一个类型。例如:用于发送通知的类,该类应根据输入参数选择正确的频道(电子邮件、sms等) 我看起来像这样: public class NotificationManager { IEmail _email; ISms _sms; public NotificationManager (IEmail email, ISMS sms) { _email = email; _sms = sms

最近我遇到了一个问题,我必须根据参数选择一个类型。例如:用于发送通知的类,该类应根据输入参数选择正确的频道(电子邮件、sms等)

我看起来像这样:

public class NotificationManager 
{
    IEmail _email;
    ISms _sms;

    public NotificationManager (IEmail email, ISMS sms) 
    {
        _email = email;
        _sms = sms;
    }

    public void Send(string type) 
    {
        switch(type) 
        {
            case "email":
                _email.send;
                break;

            case "sms":
                _sms.send;
                break;
        }
    }
}
这里的问题是,当我使用这种构造时,使用所有不同的发送通知的方法,构造函数会快速增长到非常大的规模

我真的不喜欢这样,这使得单元测试这个选择单元变得难以管理

我不能简单地说
newemail()因为通知类型的电子邮件将依赖于IEmailManager,这只会解决问题


是否有某种模式可以做到同样的效果,但会以更好、更干净的方式?

我建议您将
IEmail
ISms
接口合并到
IMessageService
(前提是不违反)中,并使用a使您的通知服务能够选择一种或多种类型所使用的
IMessageService

重构到IMessageService 或者,您也可以使用扫描自动拾取在事件发生后添加的新类型

var container = new Container(x => x.Scan(scan =>
{
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    scan.AddAllTypesOf<IMessageService>();
}));
请注意,如果采用这种方法,如果您以后决定添加或删除
IMessageService
,则您的
EmailStrategy
类将不需要更改-您只需要更改DI配置

public interface IMessageStrategy
{
    void Send(string message, string body, string provider);
    void Send(string message, string body, IEnumerable<string> providers);
}

public class MessageStrategy : IMessageStrategy
{
    private readonly IMessageService[] messageServices;

    public MessageStrategy(IMessageService[] messageServices)
    {
        if (messageServices == null)
            throw new ArgumentNullException("messageServices");
        this.messageServices = messageServices;
    }

    public void Send(string message, string body, string provider)
    {
        string[] providers = provider.Split(';').Select(p => p.ToLower().Trim()).ToArray();
        this.Send(message, body, providers);
    }

    public void Send(string message, string body, IEnumerable<string> providers)
    {
        foreach (IMessageService messageService in messageServices)
        {
            if (messageService.AppliesTo(providers))
            {
                messageService.Send(message, body);
            }
        }
    }
}
container.For<IMessageService>().Use<EmailMessageService>();
container.For<IMessageService>().Use<SmsService>();
var container = new Container(x => x.Scan(scan =>
{
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    scan.AddAllTypesOf<IMessageService>();
}));
public class SomeService : ISomeService
{
    private readonly IMessageStrategy messageStrategy;

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

    public void DoSomething()
    {
        // Send a message via email
        this.messageStrategy.Send("This is a test", "Hello", "email");

        // Send a message via SMS
        this.messageStrategy.Send("This is a test", "Hello", "sms");

        // Send a message via email and SMS
        this.messageStrategy.Send("This is a test", "Hello", "email;sms");
    }
}