SoFunction
Updated on 2025-03-07

Detailed explanation of the example of using policy mode to implement alarm service (SMS Alarm)

Let’s focus on the strategy model. First, you need to define an interface that is used to unify the alarm method, and the code is as follows:

Copy the codeThe code is as follows:

/// <summary>
/// Alarm interface, unify various alarm methods to issue alarms
/// </summary>
public interface IAlarm
{
void Alarm(Message message);
}

Will everyone be more confused when they see Message? Don’t worry. Message is an alarm model I defined myself, such as the alarm title, the recipient (to whom do you report the alarm), the alarm method (email, client, etc.).

After defining the interface, we need to implement this interface. The implementation of this interface is the classes of various alarm methods, such as and. The following is the specific implementation of email alarms, the code (the Alarm method of the IAlarm interface needs to be implemented):

Copy the codeThe code is as follows:

/// <summary>
/// Mail alarm
/// </summary>
public class EmailAlarm : IAlarm
{
/// <summary>
/// Send emails to implement the Alarm() method of the IAlarm interface
   /// </summary>
   /// <param name="messag"></param>
   public void Alarm(Message message)
   {
// Here is the specific implementation code for email alarm
   }
}

The following is the specific implementation of client alarms (Alarm() method of IAlarm interface is also required)

Copy the codeThe code is as follows:

/// <summary>
/// Client alarm
/// </summary>
public class ClientAlarm : IAlarm
{
     /// <summary>
/// Implement the Alarm() method of interface IAlarm interface
     /// </summary>
     public void Alarm(Message message)
     {
//This is the specific code for implementing the alarm on the client
     }
}

Okay, the basic work is done, the next question we face is how should we call different alarm implementations? Of course, there is an alarm method field in our alarm model Message, and we need to send different alarms according to the alarm method field. This is not simple. We generate different objects according to different alarm methods, and then call the Alarm() method to be OK. Of course, this is a workaround, but is this the best workaround? of course not! Have you heard of reflexes, friends? Next, I will introduce how to use reflection to call different alarm methods:

Copy the codeThe code is as follows:

/// <summary>
/// Classes that issue various alarms in a unified manner, encapsulate all operations that call alarms in this class. When the main program needs an alarm, just call this class directly without knowing the existence of any other class
/// </summary>
public class AlarmContext
{
private static readonly IDictionary<AlarmWay,IAlarm> _alarmsDic = new Dictionary<AlarmWay, IAlarm>();
static AlarmContext()
   {
foreach (AlarmWay way in (typeof (AlarmWay)))
       {
try
          {
Assembly asm = ();
Object obj = ("." + way + "Alarm", true);
              IAlarm alarm = obj as IAlarm;
              _alarmsDic[way] = alarm;
          }
          catch (Exception ex)
          {
("Exception occurs when constructing an alarm instance through reflection: " + ex);
          }
       }
   }

   /// <summary>
/// Call different alarm methods through transmission
   /// </summary>
   public void HandleMessage(Message message)
   {
       foreach (AlarmWay way in (typeof(AlarmWay)))
       {
//Travel through all alarm methods, each alarm method and perform bitwise and calculation. If the calculation result is still the current traversal alarm method, it means that this alarm method is included in the Message
           if (( & way) == way)
           {
               try
               {
                   _alarmsDic[way].Alarm(message);
               }
               catch (Exception ex)
               {
//Record error log
               }
            }
       }
   }
}

Is it messy again when I see AlarmWay? Don't be confused. AlarmWay is an enumeration type I defined, which contains various alarm methods. I will post the specific code at the end of the article. We are still focusing on the above code. Dear friends, have you seen the above static constructor? Do you know why you write this way? We use reflection in the static constructor to save all alarm objects in the enum in the IDictionary, and the specific storage is as follows: _alarmsDic['Email'] = (IAlarm)EmailAlarm. Friends, please think about the benefits of doing this for yourself, hehe.

Finally, we call AlarmContext in the main program to issue an alarm. The specific calling code is as follows:

Copy the codeThe code is as follows:

class Program
 {
    static void Main(string[] args)
     {
("Alarm service has been started...");
// Message should be a message that needs to be alarmed from other programs, such as getting a message in the Redis queue. The specific method depends on the needs. Here, for convenience, I generated a new object, but I shouldn't do this.
        Message message = new Message();
        AlarmContext context = new AlarmContext();
        (message);

     }
}

OK, so far, the alarm service designed using the policy model has been introduced. I think there are two main knowledge points in this article, one is the strategy model, and the other is to use reflection. I hope that all my friends will give you valuable suggestions, and finally post the code to enumerate AlarmWay:

Copy the codeThe code is as follows:

/// <summary>
/// Alarm method
/// </summary>
public enum AlarmWay
{
    Email = 1,
    Client = 2,
    ShortMessage = 4
}

By the way, let’s think about why the value of ShortMessage is 4 instead of 3?