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之美》--张子阳,感谢写了这么好的书!

原文地址:https://www.cnblogs.com/darrenji/p/3627305.html