Design patterns 如何提取具体类型的依赖关系?
我有一个要求,用户需要配置在发生错误时如何获得警报。他们有以下几种选择: 一,。在事件日志中创建事件 二,。将电子邮件发送到从用户界面指定的电子邮件Design patterns 如何提取具体类型的依赖关系?,design-patterns,dependency-injection,factory,abstract-factory,Design Patterns,Dependency Injection,Factory,Abstract Factory,我有一个要求,用户需要配置在发生错误时如何获得警报。他们有以下几种选择: 一,。在事件日志中创建事件 二,。将电子邮件发送到从用户界面指定的电子邮件 interface INotificationSender { virtual void SendMessage(string message); } 我当前使用的类使用以下接口 interface INotificationSender { virtual void SendMessage(string message); } 我
interface INotificationSender
{
virtual void SendMessage(string message);
}
我当前使用的类使用以下接口
interface INotificationSender
{
virtual void SendMessage(string message);
}
我的接口将由以下两个具体类实现
class EmailerNotificationSender: public INotificationSender
{
string m_EmailAddress;
public EmailerNotificationSender(string emailAddress)
{
m_EmailAddress = emailAddress;
}
public virtual void SendMessage(string Message)
{
// Send Message to email specified in member variable
}
}
class EventLogNotificationSender: public INotificationSender
{
public virtual void SendMessage(string Message)
{
// Log message in event log using
}
}
我当前的接口代码如下所示
public class MyUserinterfaceWindow
{
private INotificationSender m_NotificationSender; // concrete type depends on user interface selection!
public void Button_Click(...)
{
if (emailSelected)
{
m_NotificationSender = new EmailerNotificationSender(textbox.email)
return;
}
m_NotificationSender = new EventLogNotificationSender();
}
public void SendAlert()
{
m_NotificationSender.SendMessaged("SOMETHING BAD HAPPENED");
}
}
摘要/问题:
如何删除正在实例化的具体类型,例如EventLogNotificationSender和EmailerNotificationSender
注意:EventLogNotificationSender的具体构造函数不需要参数,而EmailNotificationSender的具体构造函数需要字符串参数 将两个实现隐藏在INotificationSender实现后面 如果您可以延迟用户选择要登录的源,那么可以将选择逻辑移动到组合中,这样可以防止该逻辑干扰MyUserinterfaceWindow。下面是一个例子: 公共类CompositeNotificationSender:INotificationSender{ 私人只读电子邮件通知发送人邮件; 私有只读事件日志NotificationSender事件记录器; 公共复合发送器 EmailrNotificationSender mailer, EventLogNotificationSender事件记录器{ this.mailer=mailer; this.eventLogger=eventLogger; } 公共虚拟空SendMessagestring消息{ bool logToMail=AskUserWhereToLog; var logger=logToMail?this.mailer:this.eventLogger; logger.SendMessageMessage; } 二等兵布尔阿斯库瑟霍雷托洛格{ //待办事项: } } 由于该类询问用户,因此与UI存在依赖关系,并且该类是特定于UI的。如果这不是一个选项,也可以提取它。当然,如果您愿意,您可以通过缓存结果来避免多次询问用户 如果及时询问用户不起作用,您可以创建一个CompositeNotificationSender和MyUserinterfaceWindow都可以依赖的抽象,它可以保存用户的首选项: 公共接口IUserLoggingPreference { bool LogToMail{get;set;} } MyUserinterfaceWindow或任何其他位置现在都可以依赖于IUserLoggingPreference并更改LogToMail值来更改用户的首选项。CompositeNotificationSender将如下所示: 公共类CompositeNotificationSender:INotificationSender{ 私有只读IUserLoggingPreference; 私人只读电子邮件通知发送人邮件; 私有只读事件日志NotificationSender事件记录器; 公共复合发送器 I记录偏好, EmailrNotificationSender mailer, EventLogNotificationSender事件记录器{ 这个。偏好=偏好; this.mailer=mailer; this.eventLogger=eventLogger; } 公共虚拟空SendMessagestring消息{ var logger=this.preference.LogToMail?this.mailer:this.eventLogger; logger.SendMessageMessage; } }
这样,用户单击按钮后无需提示,并且CompositeNotificationSender独立于用户界面,这使得在没有用户交互的系统部分更容易重用此逻辑,并且更容易对此类进行单元测试。为什么警报配置窗口会有SendAlert方法?如果您将用户首选项存储在某个位置,而不是在窗口中使用硬连线的m_NotificationSender,则可以根据配置在需要时动态实例化NotificationSender。