• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

c# 使用计时器和观察者模式实现报警推送需求

c# 搞代码 4年前 (2022-01-09) 15次浏览 已收录 0个评论

前言

这两天面试了一个物联网公司高级研发,面试题是下面这样子

公司领导,部门主管,小组组长,组成员4级,假如有个 疫情预警,先通知组人员(对个人,主要有一个处理就算处理了) 如果3分钟没处理,就往组长发短信,如果组长3分钟没处理就往上级推送。一级一级的。 要求单程序并发至少支持1000tps预警事件

说实话上面需求在我做的过往项目里有过类似需求,我也只是依稀记得自己是怎么做的。类似于使用第三方任务调度框架完成上面的3分钟超时处理,然后至于分级发送则更简单了,再不济就是使用if、else这样的最原始验证即可。但是这样的题目丢到面试题上我是一下就不知所措了。自然最终的结果也不尽人意(我最终提交的代码就是采用一个事件总线实现报警的推送,但是并未对其进行超时分级发送) 这个自然是错误的,我其实当时也想过使用Timer,但是内心对Timer就是感觉用性能做代价去换取最终的结果。

解析需求

过了几天还是觉得要手纯撸代码将上面功能撸出来,不然如何成长呢!
拆分下需求可以得到的消息是有一个事件。这个事件就是报警事件,通过报警事件需要将消息推送给不同职位的工作人员,而且必须遵循岗位从下至上,但凡人员收到报警消息则表示报警通知已完成,其次就是有一个三分钟需要处理。

通过上面的需求分析可以知道我们必须要定义一个枚举,记录职称高低。

  /// <summary>
  /// 工作级别
  /// </summary>
  public enum JobLevel : int
  {
    公司领导 = 1,
    部门主管 = 2,
    小组组长 = 3,
    组成员 = 4
  }

其次我们至少存在两个类,一个是产生报警的对象,这个对象有需要通知的报警信息和报警信息发送结果,当然更加少不了我们订阅了报警消息的订阅者。这里想了下,可以采用观察者设计模式进行解耦。

  /// <summary>
  /// 发布者接口
  /// </summary>
  public interface IPublish
  {
    /// <summary>
    /// 新增订阅者(观察者)
    /// </summary>
    /// <param name="subscriber"></param>
    void AddSubscriber(SubscriberPeopleBase subscriber);
 
    /// <summary>
    /// 移除订阅者(观察者)
    /// </summary>
    /// <param name="subscriber"></param>
    void RemoveSubscriber(SubscriberPeopleBase subscriber);
 
    /// <summary>
    /// 发送报警消息
    /// </summary>
    void SendNotify();
  
    /// <summary>
    /// 出现警报
    /// </summary>
    /// <param name="msg">警报消息</param>
    void CreateJB<p>本文来源gao!daima.com搞$代!码#网#</p>(string msg);

接下来就是实现上面接口了!

/// <summary>
/// 报警发布者
/// </summary>
public class Baojing : IPublish
{
    /// <summary>
    /// 订阅者集合
    /// </summary>
    public List<SubscriberPeopleBase> SubscriberLst { get; set; }
 
    /// <summary>
    /// 报警消息
    /// </summary>
    public string Msg { get; set; }
 
    /// <summary>
    /// 有无接收成功
    /// </summary>
    public bool IsSucess { get; set; }
 
    /// <summary>
    /// 消息通知计数器
    /// </summary>
    public Timer NotifyTimer { get; set; }
 
    /// <summary>
    /// 记录当前发送消息的岗位
    /// </summary>
    public JobLevel CurrentJobLevel = JobLevel.组成员;
 
    public void AddSubscriber(SubscriberPeopleBase subscriber)
    {
      if (SubscriberLst == null) SubscriberLst = new List<SubscriberPeopleBase>();
      SubscriberLst.Add(subscriber);
    }
 
    public void CreateJB(string msg)
    {
      Msg = msg;
    }
 
    public void RemoveSubscriber(SubscriberPeopleBase subscriber)
    {
      if (SubscriberLst != null) SubscriberLst.Remove(subscriber);
    }
 
 
    /// <summary>
    /// 发送报警消息
    /// </summary>
    public void SendNotify()
    {
      if (SubscriberLst?.Count > 0)
      {
        //循环从职位低到高
        SubscriberLst.OrderByDescending(p => (int)p.Title);  
         //立即执行CheckNotifySendResult,以为3秒为间隔
        NotifyTimer = new Timer(CheckNotifySendResult, null, 0, 3000);       
      }
    }
 
    public void CheckNotifySendResult(object stat)
    {
      //先要停止定时器,防止并发
      NotifyTimer.Change(-1, 3000);
      //第一次发给职位最小 枚举最大的组成员
      SubscriberPeopleBase subscriberPeople = SubscriberLst.Find(p =>
       (((int)CurrentJobLevel + 1) - (int)p.Title) == 1);
      if (subscriberPeople == null) return; //已经是最小的
      if (!IsSucess)
      {
        IsSucess = subscriberPeople.ReceiveData(this);
        if (!IsSucess)
        {
          CurrentJobLevel = CurrentJobLevel!= JobLevel.公司领导?(JobLevel)((int)CurrentJobLevel) - 1: JobLevel.公司领导;
          NotifyTimer.Change(3000, 3000);
        }
      }
      else
      {
        Console.WriteLine($"停止计数器 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        NotifyTimer.Dispose();
      }
    }
  }

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:c# 使用计时器和观察者模式实现报警推送需求

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址