我建议您将IEmail 和ISms 接口组合成IMessageService(前提是不违反Liskov Substitution Principal)并使用strategy pattern 使您的通知服务能够选择使用的IMessageService 的类型。
重构为 IMessageService
public interface IMessageService
{
void Send(string subject, string body);
bool AppliesTo(IEnumerable<string> providers);
}
public class EmailMessageService : IMessageService
{
public EmailMessageService(/* inject dependencies (and configuration) here */)
{
// Set dependencies to private (class level) variables
}
public void Send(string subject, string body)
{
// Implementation - use dependencies as appropriate
}
public bool AppliesTo(IEnumerable<string> providers)
{
return providers.Contains("email");
}
}
public class SmsMessageService : IMessageService
{
public SmsMessageService(/* inject dependencies (and configuration) here */)
{
// Set dependencies to private (class level) variables
}
public void Send(string subject, string body)
{
// Implementation - use dependencies as appropriate
}
public bool AppliesTo(IEnumerable<string> providers)
{
return providers.Contains("sms");
}
}
实施策略模式
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);
}
}
}
}
用法
在您的 DI 容器中,注册与 IMessageService 匹配的所有类型以解析为数组。例如,在 StructureMap 中:
container.For<IMessageService>().Use<EmailMessageService>();
container.For<IMessageService>().Use<SmsService>();
或者,您也可以使用 Scan 自动拾取事后添加的新类型。
var container = new Container(x => x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AddAllTypesOf<IMessageService>();
}));
无论哪种方式,只需向容器注册类型即可满足 IMessageService[] 依赖关系。
那么只需将IMessageStrategy 注入到需要消息传递的类中,并传递魔术字符串来选择要使用的消息服务类型即可。
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");
}
}
请注意,如果您采用这种方法,如果您稍后决定添加或删除 IMessageService,您的 EmailStrategy 类将不需要更改 - 您只需更改 DI 配置。