如何提取混凝土类型的依赖?

时间:2013-08-22 03:00:11

标签: design-patterns dependency-injection factory abstract-factory

我有一个要求,即用户需要配置他们希望在发生错误时收到警报的方式。他们拥有的选项如下:

1。)在事件日志中创建一个事件

2.。)向用户界面指定的电子邮件发送电子邮件

我目前使用的类使用以下界面

interface INotificationSender
{
   virtual void SendMessage(string message);
}

我的界面将由以下2个具体类

实现
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)

注意:当EmailNotificationSender的具体构造函数采用字符串参数时,EventLogNotificationSender在其具体构造函数中不需要参数!

1 个答案:

答案 0 :(得分:0)

隐藏composite INotificationSender实施背后的两个实现。

如果您可以延迟用户选择他想要记录的源,您可以将该选择逻辑移动到复合中,这可以防止此逻辑混乱MyUserinterfaceWindow。这是一个例子:

public class CompositeNotificationSender : INotificationSender {
    private readonly EmailerNotificationSender mailer;
    private readonly EventLogNotificationSender eventLogger;

    public CompositeNotificationSender(
        EmailerNotificationSender mailer,
        EventLogNotificationSender eventLogger) {
        this.mailer = mailer;
        this.eventLogger = eventLogger;
    }

    public virtual void SendMessage(string Message) {
        bool logToMail = AskUserWhereToLog();
        var logger = logToMail ? this.mailer : this.eventLogger;
        logger.SendMessage(Message);
    }

    private bool AskUserWhereToLog() {
        // TODO:
    }
}

由于此类询问用户,因此UI存在依赖关系,此类是特定于UI的。如果这不是一个选项,也可以提取。当然,如果您愿意,可以通过缓存结果来防止不得不多次询问用户。

如果要求用户及时处理不起作用,您可以创建CompositeNotificationSenderMyUserinterfaceWindow都可以依赖的抽象,以保持用户的偏好:

public interface IUserLoggingPreference
{
    bool LogToMail { get; set; }
}

MyUserinterfaceWindow(或任何其他地方)现在可以依赖IUserLoggingPreference并更改LogToMail值以更改用户的偏好。 CompositeNotificationSender将如下所示:

public class CompositeNotificationSender : INotificationSender {
    private readonly IUserLoggingPreference preference;
    private readonly EmailerNotificationSender mailer;
    private readonly EventLogNotificationSender eventLogger;

    public CompositeNotificationSender(
        IUserLoggingPreference preference,
        EmailerNotificationSender mailer,
        EventLogNotificationSender eventLogger) {
        this.preference = preference;
        this.mailer = mailer;
        this.eventLogger = eventLogger;
    }

    public virtual void SendMessage(string Message) {
        var logger = this.preference.LogToMail ? this.mailer : this.eventLogger;
        logger.SendMessage(Message);
    }
}

这样,用户无需在单击按钮后提示,CompositeNotificationSender独立于用户界面,这样可以更轻松地重用此逻辑(例如,在系统的一部分中)没有用户交互的地方)它可以更容易地对这个类进行单元测试。