• 19使用推模式和拉模式实现电梯超重报警


    当电梯超过最大承重800公斤,报警器报警。把电梯看成被观察者,报警器看成观察者。分别使用推模式和拉模式实现超重报警。

     

      推模式实现超重报警

    被观察者在运行本身方法的时候,达到一定条件,就触发通知事件,把自己的状态"推"个观察者。


    →把电梯看作是被观察者,当运行其TestWeight()方法时候,如果满足某种weight变量>800,就触发方法把自己的状态推给观察者。

       1:      //被观察者
       2:      public class Elevator : SubjectBase
       3:      {
       4:          private int weight;
       5:          private static string factory = "日立";
       6:          private static string area = "广州";
       7:   
       8:     
       9:          protected virtual void OnMoreThanStandard(MoreThanStandardEventArgs e)
      10:          {
      11:              base.Notify(e);
      12:          }
      13:   
      14:          public void TestWeight()
      15:          {
      16:              for (int i = 795; i <= 805; i++)
      17:              {
      18:                  weight = i;
      19:                  if (weight > 800)
      20:                  {
      21:                      MoreThanStandardEventArgs e = new MoreThanStandardEventArgs(weight,factory,area);
      22:                      OnMoreThanStandard(e);
      23:                  }
      24:              }
      25:          }
      26:      }

     

    →Elevator把自己的状态信息封装成MoreThanStandardEventArgs类,推送给观察者。

       1:      //观察者和被观察者之间传递的参数
       2:      public class MoreThanStandardEventArgs
       3:      {
       4:          private int weight;
       5:          private string factory;
       6:          private string area;
       7:   
       8:          public MoreThanStandardEventArgs(int weight, string factory, string area)
       9:          {
      10:              this.weight = weight;
      11:              this.factory = factory;
      12:              this.area = area;
      13:          }
      14:   
      15:          public int Weight {get { return weight; }}
      16:          public string Factory {get { return factory; }}
      17:          public string Area {get { return area; }}
      18:      }

     

    →Elevator本身没有注册、注销、通知观察者的能力,所以需要继承有这些能力的基类SubjectBase。

       1:     //被观察者基类抽象类
       2:      public abstract class SubjectBase : IObseervable
       3:      {
       4:          private List<IObserver>  container = new List<IObserver>();
       5:          public void Register(IObserver obj)
       6:          {
       7:              container.Add(obj);
       8:          }
       9:   
      10:          public void Unregister(IObserver obj)
      11:          {
      12:              container.Remove(obj);
      13:          }
      14:   
      15:          protected virtual void Notify(MoreThanStandardEventArgs e)
      16:          {
      17:              foreach (IObserver observer in container)
      18:              {
      19:                  observer.Update(e);
      20:              }
      21:          }
      22:      }

     

    →而IObservalble的接口就注册和取消注册2个行为。

       1:      //被观察者接口
       2:      public interface IObseervable
       3:      {
       4:          void Register(IObserver obj);
       5:          void Unregister(IObserver obj);
       6:      }    

     

    →观察者接口拿到被观察者推来的信息,做自己的事。

       1:      //观察者接口
       2:      public interface IObserver
       3:      {
       4:          void Update(MoreThanStandardEventArgs e);
       5:      }

     

    →观察者就把状态信息显示出来

       1:      //观察者
       2:      public class Alarm : IObserver
       3:      {
       4:          public void Update(MoreThanStandardEventArgs e)
       5:          {
       6:              Console.WriteLine("嘀嘀嘀:来自{0}{1}的电梯最大承重800kg,目前重量为{2}",e.Area,e.Factory,e.Weight);
       7:          }
       8:      }

     

    →主程序

       1:      class Program
       2:      {
       3:          static void Main(string[] args)
       4:          {
       5:              Elevator elevator = new Elevator();
       6:              Alarm alarm = new Alarm();
       7:   
       8:              elevator.Register(alarm);
       9:              elevator.TestWeight();
      10:              Console.ReadKey();
      11:          }
      12:      }


    结果:
    1

     

      拉模式实现超重报警   

    观察者把被观察者拉进来作为方法参数,当被观察者在运行本身方法的时候,达到一定条件,就触发通知事件,并把自己传递给观察者方法。

     

    →被观察者Elevator执行方法满足条件就触发通知

       1:      //被观察者
       2:      public class Elevator : SubjectBase
       3:      {
       4:          private int weight;
       5:          private static string factory = "日立";
       6:          private static string area = "广州";
       7:   
       8:          public int Weight {get { return weight; }}
       9:          public string Factory {get { return factory; }}
      10:          public string Area {get { return area; }}
      11:   
      12:          protected virtual void OnMoreThanStandard()
      13:          {
      14:              base.Notify(this);
      15:          }
      16:   
      17:          public void TestWeight()
      18:          {
      19:              for (int i = 795; i <= 805; i++)
      20:              {
      21:                  weight = i;
      22:                  if (weight > 800)
      23:                  {
      24:                      OnMoreThanStandard();
      25:                  }
      26:              }
      27:          }
      28:      }
      29:   

     

    →被观察者Elevator本身没有注册、取消注册、通知观察者的能力,需要继承拥有这些能力的SubjectBase。 

       1:      //被观察者基类
       2:      public abstract class SubjectBase : IObservable
       3:      {
       4:          List<IObserver>  container = new List<IObserver>();
       5:   
       6:          public void Register(IObserver obj)
       7:          {
       8:              container.Add(obj);
       9:          }
      10:   
      11:          public void Unregister(IObserver obj)
      12:          {
      13:              container.Remove(obj);
      14:          }
      15:   
      16:          protected virtual void Notify(IObservable obj)
      17:          {
      18:              foreach (IObserver observer in container)
      19:              {
      20:                  observer.Update(obj);
      21:              }
      22:          }
      23:      }

     

    →观察者调用自己拉进来的观察者对象获得其状态信息

       1:      //观察者接口
       2:      public interface IObserver
       3:      {
       4:          void Update(IObservable sender);
       5:      }
       6:   
       7:      //观察者
       8:      public class Alarm : IObserver
       9:      {
      10:          public void Update(IObservable sender)
      11:          {
      12:              Elevator elevator = (Elevator)sender;
      13:              Console.WriteLine("嘀嘀嘀:来自{0}{1}的电梯最大承重800kg,目前重量为{2}", elevator.Area, elevator.Factory, elevator.Weight);
      14:          }
      15:      }   

     

    → 主程序

       1:      class Program
       2:      {
       3:          static void Main(string[] args)
       4:          {
       5:              Elevator elevator = new Elevator();
       6:              Alarm alarm = new Alarm();
       7:   
       8:              elevator.Register(alarm);
       9:              elevator.TestWeight();
      10:              Console.ReadKey();
      11:          }
      12:      }

     

    结果:

    1

     

      推模式和拉模式的区别

    ● 推模式的好处是按需供给:观察者需要什么状态信息,被观察者就把需要的状态信息封装起来推给观察者。缺点是需要创建封装的状态信息。
    ● 拉模式的好处是不需要创建推送给观察者的、封装状态的信息。缺点是把被观察者的属性和方法暴露给了被观察者。

     

    而微软定义的委托EventHandler则很好解决了推和拉的问题,不仅可以拿到被观察者本身,同时可以拿到观察者的状态信息:

    public delegate void EventHandler(object sender, EventArgs e)

     

    参考资料:
    《.NET之美》--张子阳,感谢写了这么好的书!

  • 相关阅读:
    三剑客之Grep家族
    Linux默认权限命令:umask
    Linux特殊权限管理SUID|SGID|STICKY
    zabbix的web界面出现乱码解决方案
    启动zabbix-server/agent报错:cannot open "/etc/zabbix/logs/zabbix_server.log": [13] Permission denied
    Zabbix-Agent配置文件详解
    使用yum安装报错:[Errno 256] No more mirrors to try
    grep/sed/awk命令查看指定时间段的日志
    数据库SQL练习(一):数据查询
    连接数据库报错:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
  • 原文地址:https://www.cnblogs.com/darrenji/p/3627305.html
Copyright © 2020-2023  润新知