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

前言

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

公司领导,部门主管,小组组长,组成员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(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();
      }
    }
  }

还需要有订阅者,订阅者使用抽象类方式降低耦合性(其实还是要用事件总线,将耦合性和扩展性提高一个档次)

 /// <summary>
  /// 订阅者
  /// 其实这里还不够完善,理论上后续如果每个职位的订阅者对报警消息的处理不同则在下面的接收消息里会存在一些冗余代码,
  /// 理想情况是不同级别应该有不同的实现,这样可以足够抽象,后续扩展也更加方便
  /// </summary>
  public abstract class SubscriberPeopleBase
  {
    /// <summary>
    /// 工作职位(级别)
    /// </summary>
    public JobLevel Title { get; set; }

    public SubscriberPeopleBase(JobLevel title)
    {
      Title = title;
    }

    public virtual bool ReceiveData(Baojing baojing)
    {
      if (Title == JobLevel.公司领导)
      {
        Console.WriteLine($"出现报警信息:{baojing.Msg},当前订阅者:{Title.ToString()} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        return true;
      }
      else
      {
        Console.WriteLine($"出现报警信息:{baojing.Msg},当前订阅者:{Title.ToString()},默认未应答 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        return false;
      }
    }
  }

再加个子类,重写下接收警报的方法

public class SubscriberPeople : SubscriberPeopleBase
 {
    public SubscriberPeople(JobLevel title) : base(title) { }
    public override bool ReceiveData(Baojing baojing)
    {
      if (Title == JobLevel.公司领导)
      {
        Console.WriteLine($"出现最新报警信息:{baojing.Msg},当前订阅者:{Title.ToString()} 已成功应答 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        return true;
      }
      else
      {
        Console.WriteLine($"出现报警信息:{baojing.Msg},当前订阅者:{Title.ToString()},默认未应答 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        return false;
      }
    }
 }

最终我的main方法是这样

 static void Main(string[] args)
 {
      IPublish publish = new Baojing();
      publish.AddSubscriber(new SubscriberPeople(JobLevel.组成员));
      publish.AddSubscriber(new SubscriberPeople(JobLevel.公司领导));
      publish.AddSubscriber(new SubscriberPeople(JobLevel.部门主管));
      publish.AddSubscriber(new SubscriberPeople(JobLevel.小组组长));
      publish.CreateJB("主机温度过高!");
      publish.SendNotify();
      Console.ReadLine();
  }

调试的效果如下:

明天还是完善下,将使用EventBus,将耦合性再度降低,同时也能让接收方法更加灵活性,能实现不同级别的职员做出不同的响应!

以上就是c# 使用计时器和观察者模式实现报警推送需求的详细内容,更多关于c# 实现报警推送需求的资料请关注我们其它相关文章!

(0)

相关推荐

  • C#中各种计时器用法小结

    本文实例总结了C#中各种计时器用法.分享给大家供大家参考,具体如下: 1.使用 Stopwatch 类 (System.Diagnostics.Stopwatch) Stopwatch 实例可以测量一个时间间隔的运行时间,也可以测量多个时间间隔的总运行时间.在典型的 Stopwatch 方案中,先调用 Start 方法,然后调用 Stop 方法,最后使用 Elapsed 属性检查运行时间. Stopwatch 实例或者在运行,或者已停止:使用 IsRunning 可以确定 Stopwatch 的

  • C#设计模式之Observer观察者模式解决牛顿童鞋成绩问题示例

    本文实例讲述了C#设计模式之Observer观察者模式解决牛顿童鞋成绩问题.分享给大家供大家参考,具体如下: 一.理论定义 观察者模式 描述了 一种 一对多的关系. 当某一对象的状态发生改变时,其他对象会得到 改变的通知.并作出相应的反应. 二.应用举例 需求描述:牛顿同学的期末考试成绩(Score)出来了,各科老师都想知道自己的 学生 成绩情况! 语文老师(TeacherChinese)只关心  牛顿的语文(Chinese)成绩. 英语老师(TeacherEnglish)只关心  牛顿的英语(

  • C# 设计模式系列教程-观察者模式

    1. 概述 有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 2. 解决的问题 将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性.我们不希望为了维持一致性而使各类紧密耦合,这样会给维护.扩展和重用都带来不便.观察者就是解决这类的耦合关系的. 3. 模式中的角色 3.1 抽象主题(Subject):它把所有观察者对象的引用保存

  • C#中计时器的简单实现方法示例

    本文实例讲述了C#中计时器的简单实现方法.分享给大家供大家参考,具体如下: startTime = DateTime.Now; DispatcherTimer dt = new DispatcherTimer(); dt.Interval = new TimeSpan(0, 0, 1); dt.Tick += new EventHandler(dt_Tick);//调用函数 dt.Start(); void dt_Tick(object sender, EventArgs e) { timeSp

  • C#中观察者模式的3种实现方式

    说起观察者模式,估计在园子里能搜出一堆来.所以写这篇博客的目的有两点: 1.观察者模式是写松耦合代码的必备模式,重要性不言而喻,抛开代码层面,许多组件都采用了Publish-Subscribe模式,所以我想按照自己的理解重新设计一个使用场景并把观察者模式灵活使用在其中 2.我想把C#中实现观察者模式的三个方案做一个总结,目前还没看到这样的总结 现在我们来假设这样的一个场景,并利用观察者模式实现需求: 未来智能家居进入了每家每户,每个家居都留有API供客户进行自定义整合,所以第一个智能闹钟(sma

  • C#线程倒计时器源码分享

    本文实例为大家分享了C#线程倒计时器源码,供大家参考,具体内容如下 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Windows.Forms; namespace ListZZBG { class TimeHeleper { Thread thread; private TimeSpan time;

  • C#计时器的三种实现方法

    在.NET中有三种计时器: 一. System.Windows.Forms命名空间下的Timer控件,和所在的Form属于同一个线程.Timer控件只有绑定了Tick事件和设置Enabled属性为True之后才会自动计时,Stop()方法,Start()方法启动计时器重新计时: MyTimer.Enabled = true;  //启动计时器 MyTimer.Interval = 1000; //设置计时器时间间隔,单位为ms MyTimer.Stop(); //停止计时 MyTimer.Sta

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

    前言 这两天面试了一个物联网公司高级研发,面试题是下面这样子 公司领导,部门主管,小组组长,组成员4级,假如有个 疫情预警,先通知组人员(对个人,主要有一个处理就算处理了) 如果3分钟没处理,就往组长发短信,如果组长3分钟没处理就往上级推送.一级一级的. 要求单程序并发至少支持1000tps预警事件 说实话上面需求在我做的过往项目里有过类似需求,我也只是依稀记得自己是怎么做的.类似于使用第三方任务调度框架完成上面的3分钟超时处理,然后至于分级发送则更简单了,再不济就是使用if.else这样的最原

  • 漂流瓶推送需求的逻辑实现代码

    本身这两个数据之间没有关联,并且sql语句里面的排序规则不能满足要求:sql里只有数据中前一个排序条件出现相同的情况时才考虑后面的排序条件.实际情况是如果按先推送时间后距离排序的话,距离就起不了作用,反之亦然. 要让两个数据产生关联,有一种做法是将这两个数据做加法或减法后排序,但是这必须要考虑以下情况 两个数据的数据类型不一致,一个是日期类型另一个是双精度类型 必须统一两个数据的排序方向,不能推送时间取正序而距离取反序,视实际需求而定 将这两个数据都转换成一种类型,需要一个系数来平衡它们.如果一

  • 利用 Go 语言编写一个简单的 WebSocket 推送服务

    本文中代码可以在 github.com/alfred-zhong/wserver获取. 背景 最近拿到需求要在网页上展示报警信息.以往报警信息都是通过短信,微信和 App 推送给用户的,现在要让登录用户在网页端也能实时接收到报警推送. 依稀记得以前工作的时候遇到过类似的需求.因为以前的浏览器标准比较陈旧,并且那时用 Java 较多,所以那时候解决这个问题就用了 Comet4J.具体的原理就是长轮询,长链接.但现在毕竟 html5 流行开来了,IE 都被 Edge 接替了,再用以前这种技术就显得过

  • Java应用层协议WebSocket实现消息推送

    目录 前言 浏览器端 服务器端 前言   大部分的web开发者,开发的业务都是基于Http协议的:前端请求后端接口,携带参数,后端执行业务代码,再返回结果给前端.作者参与开发的项目,有一个报警推送的功能,服务端实时推送报警信息给浏览器端:还有像抖音里面,如果有人关注.回复你的评论时,抖音就会推送相关消息给你了,你就会收到一条消息.   有些同学会说了,基于Http协议也能实现啊:前端定时访问后端(每隔3s或者几秒),后端返回消息数据,前端拿到后弹出消息.这种方式太low了,而且每个浏览器都这样,

  • iOS中关于信鸽推送的使用demo详解

    最近在看推送方面的知识,用的是信鸽推送主要是因为后台用的是信鸽 推送用第三方推送,也就是在客户端建一个广播接收器,当服务器发送消息时发送到信鸽,信鸽再发送一次,广播接受器接受下: 我实现的功能比较简单,当app在运行状态时,会在主页展示一个弹窗展示推送的消息:如果app不在运行状态且service没被销毁就展示默认的通知 那么如何在主页展示弹窗:当广播接受器收到我要的消息时,用观察者模式,收到消息在发送个消息个主界面 官方的Demo连接:http://xg.qq.com/xg/help/ctr_

  • python3实现钉钉消息推送的方法示例

    背景 偶然发现一个python实现的按照农历/阴历推送消息提醒的程序,钉钉群消息推送.此处总结并对其可推送的消息做. DingtalkNotice 环境:python3.7 安装: pip install schedule #实现定时任务的模块 pip install DingtalkChatbot #python封装的各种消息的调用 pip install sxtwl #日历库 钉钉自定义机器人: 钉钉群机器人是一个高级扩展的功能,可以将第三方服务的信息聚合到钉钉群众,实现信息的自动化同步.1

  • Android采用消息推送实现类似微信视频接听

    本文实例为大家分享了Android实现类似微信视频接听的具体代码,供大家参考,具体内容如下 1.背景需求:业务需要接入视频审核功能,在PC 端发起视频通话,移动端显示通话界面点击接听后进行1对1视频通话. 2.解决方案:因为项目没有IM功能.只集成了极光消息推送(极光消息推送接入参考官方文档,经过跟需求沟通,采用消息推送调起通话接听界面.再集成腾讯实时音视频SDK(具体集成方式参考官方文档).最终实现类似微信1对1通话功能. 3.技术实现: A:编写一个广播接收器,并且在 AndroidMani

  • 本地推送通知UserNotifications在Swift中的实现方式

    简介 消息推送相信在很多人的眼里都不陌生了吧?像即时聊天微信,好友发信息给你时会在顶部弹下小窗口提醒你.也像是在影院APP预订了电影票,在开场前一小时你也会收到提醒.这类推送是需要经过后端发送请求的,需要服务器发送推送请求,又或者使用如极光推送等第三方渠道. 那么如果我们的APP不需要连网呢?这是不是就不能使用消息推送了?不是的,苹果还提供给我们本地消息通知服务,即便APP不连网也能使用,功能也很强大可靠.本地时钟的应用场景很广泛,例如手机上的时钟.日历等. 那么你知道如何去实现它吗?这篇文章将

  • java实现web实时消息推送的七种方案

    目录 引言 什么是消息推送(push) 短轮询 长轮询 iframe流 SSE (我的方式) MQTT Websocket 自定义推送 Github地址 引言 做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能. 不过他还没想好用什么方式做,这里我帮他整理了一下几种方案,并简单做了实现. 案例下载 什么是消息推送(push) 推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用. 消息推送(push)通常是

  • 使用 Javascript 实现浏览器推送提醒功能的示例

    本篇文章内容简单,速读只需两三分钟,通过这两三分钟的时间你就可以给自己的网站实现推送提醒的功能 Notification 类 简单明了,这个类就是负责推送消息的,只要用户当前没有关闭页面,及时是在使用其他程序,浏览器也能够将消息推送给用户 请求权限 我们在手机上都收到过消息推送,在接收推送之前我们会先将消息推送权限开放给应用.在浏览器中也一样,在使用浏览器推送之前,需要先获取权限 Notification.requestPermission().then(permission => { cons

随机推荐