C# 在运行时决定调用哪个类
在我的方法中,我必须决定如何处理传入的数据。这些对象包含一个字符串,该字符串定义了如何处理它们 目前我有以下课程:C# 在运行时决定调用哪个类,c#,.net-core,C#,.net Core,在我的方法中,我必须决定如何处理传入的数据。这些对象包含一个字符串,该字符串定义了如何处理它们 目前我有以下课程: interface INotifier{ string Name { get; } Task SendNotification(Notification); } public class WhatsappNotifier : INotifier{ public string Name => "whatsapp"; public async T
interface INotifier{
string Name { get; }
Task SendNotification(Notification);
}
public class WhatsappNotifier : INotifier{
public string Name => "whatsapp";
public async Task SendNotification(Notification notification){
//Handle notification
}
}
public class EmailNotifier : INotifier{
public string Name => "email";
public async Task SendNotification(Notification notification){
//Handle notification
}
}
public class NotificationCoordinator{
private readonly INotifier[] _notifiers;
public NotificationCoordinator(EmailNotifier emailNotifier, WhatsappNotifier whatsappNotifier){
_notifiers = new INotifier[]
{
emailNotifier,
whatsappNotifier
};
}
public async Task HandleNotifications(Notification[] notifications){
INotifier notifier = null;
foreach(Notification notification in notifications){
notifier = _notifiers.Where(n => n.Name == notification.Type).FirstOrDefault();
if(notifier != null)
await notifier.SendNotification(notification);
}
}
}
根据通知的type属性,它选择正确的通知程序类来处理通知业务。这很好,但我从一位同事那里得到了一些反馈,认为这可以用更好的方式来实现,但我不确定如何实现。是否有适合此场景的设计模式?在您的示例中,您使用的是“策略”模式。无论如何,它没有完全正确地实现,因为您的类
NotificationCoordinator
违反了单一责任原则。在这种情况下,您应该将“应该使用哪个INotifier”的决策过程委托给单独的类,例如:
public class NotificationStrategy : INotificationStrategy
{
private readonly IEmailNotifier _emailNotifier;
private readonly IWhatsappNotifier _whatsappNotifier;
public NotificationStrategy(IEmailNotifier emailNotifier, IWhatsappNotifier whatsappNotifier)
{
_emailNotifier = emailNotifier;
_whatsappNotifier = whatsappNotifier;
}
public INotifier GetNotifier(Notification notification)
{
// Notifies selection logic HERE
}
}
现在,您必须更改
NotificationCoordinator
CTOR,并使用NotificationStrategy
作为依赖项。接下来在HandleNotifications
中,使用GetNotifier
获取正确的通知程序。当然,您应该避免使用具体的类,例如,通知
——您应该用一些抽象来代替它。我不会说这个解决方案更好,但至少是不同的,它基于依赖注入:
public class Notification
{
public string Type { get; set; }
public string Body { get; set; }
public string Recipients { get; set; }
}
public interface INotifier
{
Task SendAsync(Notification notification);
}
public class WhatsAppNotifier : INotifier
{
public Task SendAsync(Notification notification)
{
throw new NotImplementedException();
}
}
public class EmailNotifier : INotifier
{
public Task SendAsync(Notification notification)
{
throw new NotImplementedException();
}
}
public class NotifierFactory
{
private readonly IServiceProvider serviceProvider;
public NotifierFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public INotifier Get(string name)
{
return serviceProvider.GetNotifier(name);
}
}
public class GeneralNotifier : INotifier
{
private readonly NotifierFactory notifierFactory;
public GeneralNotifier(NotifierFactory notifierFactory)
{
this.notifierFactory = notifierFactory;
}
public Task SendAsync(Notification notification)
{
var notifier = notifierFactory.Get(notification.Type);
return notifier.SendAsync(notification);
}
}
public class BulkNotifier
{
private readonly INotifier notifier;
public BulkNotifier(INotifier notifier)
{
this.notifier = notifier;
}
public async Task SendNotificationsAsync(IEnumerable<Notification> notifications)
{
foreach (var notification in notifications)
{
await notifier.SendAsync(notification);
}
}
}
public static class DependencyInjection
{
private static Dictionary<string, Type> notifierByName = new Dictionary<string, Type>();
private static IServiceCollection AddScopedNotifier<T>(this IServiceCollection services, string name) where T: class, INotifier
{
notifierByName[name] = typeof(T);
return services.AddScoped<T>();
}
public static INotifier GetNotifier(this IServiceProvider serviceProvider, string name)
{
if (!notifierByName.TryGetValue(name, out Type notifierType))
{
throw new KeyNotFoundException($"{name} notifier is not registered with the depencency injection container. Please call IServiceCollection.AddNotifier");
}
return (INotifier)serviceProvider.GetRequiredService(notifierType);
}
public static IServiceCollection AddNotifiers(this IServiceCollection services)
{
return services
.AddScopedNotifier<WhatsAppNotifier>("whatsapp")
.AddScopedNotifier<EmailNotifier>("email")
.AddScoped(serviceProvider => new NotifierFactory(serviceProvider))
.AddScoped<INotifier, GeneralNotifier>()
.AddScoped<BulkNotifier>();
}
}
“那么你的服务和控制器就可以依赖于
BulkNotifier
或INotifier
问问你的同事,”他这样说。对你同事来说,那是一个毫无用处的评论。有很多不同的方法可以做到这一点。使用字典
,使用访客模式。。。有些可能执行得更好,有些可能比其他更可读,有些可能更易于维护。。。这取决于他对“更好”的定义。说得对。这家伙很忙,应该还需要更多的信息。我看不出有什么理由在这里同时设置NotificationCoordinator
和NotificationStrategy
NotificationCoordinator
实际上做了一件事,实施策略,为什么要添加另一个抽象?我与@Beyers分享这个问题。添加的抽象似乎没有必要。我也不太明白你在避免具体类通知背后的想法?Notification类只是一个独立的模型,其中包含数据,如要发送的消息。@RobinAnderPlas。。。然而,它“知道”通过什么方式发送。但我们现在可以转移到没完没了的架构讨论中。事实是:优化的目标是什么?这是这个问题的正确答案吗?它能正常工作吗?也许更适合CodeReview。。。拜耳,罗宾,如果你不知道为什么你应该分离这些顾虑,那么你必须阅读坚实的原则。在od通知和“抽象”的情况下,您可能是对的,但前提是它是一个POCO对象——您没有显示它的实现,所以很难说。在我的回答中,我还假设你知道什么是DI,并且你使用它。正如你们所说,你们的实现是有效的,它会一直有效,直到你们不得不改变一些事情,然后问题就会出现;)@Posio我不是反对SOLID。我的问题是,你为什么认为通知协调员违反了单一责任原则?它实际上只做一件事,那就是实施战略。
services.AddNotifiers();