• Design patterns
  • Kata

Kata2: The Decorator Pattern

This the second part of the series of Coding Kata’s. Here we’ll explore the Decorator pattern.

[Image no longer available]

This is the user story:

You need to send alerts to your customers when a new product is available.
An Alert is represented by the Alert Class:

public class Alert
{
      public String DestinationAddress { get; set; }
      public String SenderAddress { get; set; }
      public String Content { get; set; }
      public string Log { get; set; }
}

Classes used to send the Alerts implement the following interface:

public interface ISender
{
        void Send(Alert alert);
}
  • Create an Alerter class that send the appropriate alerts.
  • Alerts are always send by e-mail.
  • Customers can also subscribe to receive alerts via sms and/or through messenger.
  • Use the Decorator pattern to configure the Alerter

You do not need to use real infrastructure code to send the alert, just append a string that contains the Sender through which the message was send.
->Append the following text to the Alert.Log when the message is send by:

  • e-mail: “Message was send by e-mail”
  • sms: “Message was send by sms”
  • messenger: “Message was send by messenger”

Solution

using System;
using NUnit.Framework;

namespace Kata2
{
    #region Tests
    [TestFixture]
    public class AlerterTest
    {
        [Test]
        public void SendAlert_ThroughEmailSender_SendEmail()
        {
            //Arrenge
            var sender = new EmailSender();
            var subject = new Alerter(sender);
            var message = new Alert();

            //Act
            subject.Send(message);

            //Assert
            Assert.AreEqual(LogConstants.SendByEmail, message.Log);
        }

        [Test]
        public void SendAlert_ThroughSmsSender_SendEmailAndSms()
        {
            //Arrenge
            var emailSender = new EmailSender();
            var smsSender = new SmsSender(emailSender);
            var subject = new Alerter(smsSender);
            var message = new Alert();

            //Act
            subject.Send(message);

            //Assert
            Assert.AreEqual(LogConstants.SendByEmail + LogConstants.SendBySMS, message.Log);
        }

        [Test]
        public void SendAlert_ThroughMessengerSenderWithEmailSender_SendEmailAndMessengerAlert()
        {
            //Arrenge
            var emailSender = new EmailSender();
            var messengerSender = new MessengerSender(emailSender);
            var subject = new Alerter(messengerSender);
            var message = new Alert();

            //Act
            subject.Send(message);

            //Assert
            Assert.AreEqual(
                LogConstants.SendByEmail + LogConstants.SendByMessenger
                , message.Log
                );
        }

        [Test]
        public void SendAlert_ThroughMessengerSenderWithSmsSender_SendEmailAndSmsAndMessengerAlert()
        {
            //Arrenge
            var emailSender = new EmailSender();
            var smsSender = new SmsSender(emailSender);
            var messengerSender = new MessengerSender(smsSender);
            var subject = new Alerter(messengerSender);
            var message = new Alert();

            //Act
            subject.Send(message);

            //Assert
            Assert.AreEqual(
                LogConstants.SendByEmail + LogConstants.SendBySMS + LogConstants.SendByMessenger
                , message.Log
                );
        }

    }
    #endregion

    #region Decorators
    public class MessengerSender: ISender
    {
       private ISender _sender;
       public MessengerSender(ISender sender)
        {
            _sender = sender;
        }

        public void Send(Alert message)
        {
            _sender.Send(message);
            //Here we would send a messenger alert
            message.Log += LogConstants.SendByMessenger;
        }
    }

    public class SmsSender : ISender
    {
        private ISender _sender;
        public SmsSender(ISender sender)
        {
            _sender = sender;
        }

        public void Send(Alert message)
        {
            _sender.Send(message);
	     //Here we would send the SMS
            message.Log += LogConstants.SendBySMS;
        }
    }
    #endregion

    #region  Component
    public class EmailSender : ISender
    {
        public void Send(Alert message)
        {
            //Here we would send an e-mail
            message.Log = LogConstants.SendByEmail;
        }
    }

    public interface ISender
    {
        void Send(Alert message);
    }
    #endregion

    #region Client
    public class Alerter
    {
        private ISender _sender;
        public Alerter(ISender sender)
        {
            _sender = sender;
        }

        public void Send(Alert message)
        {
            _sender.Send(message);
        }
    }
    #endregion

    #region Other
    public class Alert
    {
        public String DestinationAddress { get; set; }
        public String SenderAddress { get; set; }
        public String Content { get; set; }
        public string Log { get; set; }
    }

    public class LogConstants
    {
        public const string SendByEmail = "Message was send by e-mail /n";
        public const string SendBySMS = "Message was send by sms /n";
        public const string SendByMessenger = "Message was send by messenger /n";
    }
    #endregion
}