`

C# - Dabble with IObservable<T> and IObserver<T>

    博客分类:
  • C#
c# 
阅读更多

Delegate offers some nice features of observable pattern, however, there are some limiation on the delgate implemented observable patterns.

 

Why not Delegate

 

For onething, there is no way to know when the subject no longer tick; the subject may become out of interest if it does not tick updates; But with the passive mode of delegate, you do not know that a subject is become inactive as the pattern itself is passive (there are some workaround , indeed by you provide another event to nofity that the subject is beome inactive);

 

For another, there is no way to descrimate against a valid udpate from error conditions, using some sentry value as the update event args could serve in some cases, but that is a botch/tinker/bumble/bungle rather than good solution, it is a smell design to intermingle the normal message channel with the error message channel;

 

for yet another, there is no way to know when/how to remove the IObserver from the notification list, a simple -= may unsusbscribe the event listener, but there would exist a huge amount of house keeping work that needs to be addresseed when an Observer go out of scope. Better, a Disposable is better in situation like this; 

 

 

IObservable<T> and IObserver<T> pattern provides the cure;

 

It has provide the following.

the return value of IDisposable, which satisify the the question of "how to remove teh IObserver from the notification list";

this has the functionality of telling the observers when the subject (provider) will/has become inactive. and on receiving the information, teh IObserver can use the IDispose method that it receives in the Subscribe step to unsubscibe itself from the notification and do the proper uninitialization.

  • IObserver<T>.OnNext(): this satisfy the basic requirement of the Provider notifies the clien when there is update coming.

 

Below shows the code an example IObservable<T> implementation, the T is of type Location, which represent some Location information.

 

 

 

namespace PushBasedNotificationTest
{
  public struct Location
  {

    double lat, lon;

    public Location(double latitude, double longitude)
    {
      this.lat = latitude;
      this.lon = longitude;
    }

    public double Latitude
    {
      get { return this.lat; }
    }
    public double Longitude
    {
      get { return this.lon; }
    }

  }
}
 

 

LocationTracker is our impl  of IObservable<Location>, here it is:

 

 

namespace PushBasedNotificationTest
{
  public class LocationTracker  : IObservable<Location>
  {
    public LocationTracker()
    {
      // initialize the list of Observers to the Updates
      observers = new List<IObserver<Location>>();
    }

    // you need a collection of Observers
    // on which you can send the notification 
    private List<IObserver<Location>> observers;


    // Subscribe an observer (IObserver<T>) to the observer list
    // notice the return value of the Subscribe method, 
    // which is of type IDisposable.
    // normally the Observer will store the return value 
    // and call the Dispose method from the IDisposable interface 
    // the common work done in the Disposable method is to remove itself from the 
    // notification list;
    public IDisposable Subscribe(IObserver<Location> observer)
    {
      if (!observers.Contains(observer))
        observers.Add(observer);

      return new Unsubscriber(observers, observer);

    }


    // the Unsubscriber will be returned to Observer
    // which on dispose, can remove itself from the 
    // notification list, 
    // so it makes sense to extends the Unsubscriber from the 
    // interface IDisposable
    // 
    // Another note about the IDisposable implementation is that 
    // the IObservable interface can hide the implementation inside its body
    // client to IObservable should not be aware of the implementation of the 
    // interface, thus have better decoupling
    private class Unsubscriber : IDisposable
    {

      public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
      {
        _observers = observers;
        _observer = observer;
      }


      private List<IObserver<Location>> _observers;
      private IObserver<Location> _observer;

      public void Dispose()
      {
        if (_observer != null && _observers.Contains(_observer))
          _observers.Remove(_observer);
      }

    }

    // though I think it is better to call the method Update
    // as what it does it to notify the observers that has registered to
    // itself ; 
    // the notification is done by send message to the 
    //  OnComplete
    //  OnNext
    //  OnError
    // method of the IObserver<T> interface
    // the IObserver<T> interface can decide what action to take on 
    // receiving the message on different channels.
    // 
    public void TrackLocation(Nullable<Location> loc)
    {
      foreach (var observer in observers)
      {
        if (!loc.HasValue)
        {
          observer.OnError(new LocationUnknownException());
        }
        else
        {
          observer.OnNext(loc.Value);
        }
      }
    }

    // Or I think a better name could be 
    // EndUpdate
    // because what it does it to signal the end of updates 
    // from this very IObservable interface
    public void EndTransmission()
    {
      foreach (var observer in observers.ToArray())
      {
        if (observers.Contains(observer))
          observer.OnCompleted();
      }
      // Is it necessary to do the 
      //  IList.Clear() call?
      // because the IObserver<T> method should have the necessary Dispose method to remove 
      // the list...
      // However, I think as a defensive means, it is necessary
      observers.Clear();
    }
  }
}
 

and the LocationReporter is the Observer which implements the IObserver<Location> interface:

 

 

namespace PushBasedNotificationTest
{
  public class LocationReporter : IObserver<Location>
  {
    // Remeber what we have said before, we subscribe the IObserver
    // and we get back a IDisposable 
    // instance, the intance will helps us do the necessary disposition
    private IDisposable unsubscriber;

    private string instName;

    public LocationReporter(string name)
    {
      this.instName = name;
    }

    public string Name { get { return instName; } }


    // you can further encapsulate the IObservable<T> interface.Subscriber method
    // by the encapsulation, you can store the return value of the 
    // IDisposable instance locally.
    // The benefit is that you can chain the Disposble method to destroy the 
    // subscription once the ISubscriber is dead
    public virtual void Subscribe(IObservable<Location> provider)
    {
      if (provider != null)
        unsubscriber = provider.Subscribe(this);
    }

    public virtual void OnCompleted()
    {
      Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", this.Name);
    }

    // The contract of the OnError is Exception E
    // where you can have subsclass of Exception passed in to indicate a specific kind of 
    // error has happened
    public virtual void OnError(Exception e)
    {
      Console.WriteLine("{0}: The locatino cannot be determined.", this.Name);
    }

    public virtual void OnNext(Location value)
    {
      Console.WriteLine("{2}: the current location is {0}, {1}", value.Latitude, value.Longitude, this.Name);
    }

    // you can actually inherits the LocationReporter from IDisposable
    // where you can chain the Dispose method together
    public virtual void Unsubscribe()
    {
      unsubscriber.Dispose();
    }
  }
}

 

 

To communicate the eror condition, we will use the LocationException message as follow. 

 

 

 

namespace PushBasedNotificationTest
{
  //  this is a custom type Exception  that 
  // you may pass to the OnError Notification channel of
  // IObserver<T> interface.
  public class LocationUnknownException : Exception
  {
    internal LocationUnknownException()
    { }
  }
}
 

The last point, is the drive class that wires up the Observer and their Observables.

 

 

namespace PushBasedNotificationTest
{
  class Program
  {
    static void Main(string[] args)
    {
      // Define a provider and two observers
      LocationTracker provider = new LocationTracker();
      LocationReporter reporter1 = new LocationReporter("FixedGPS");
      reporter1.Subscribe(provider);
      LocationReporter reporter2 = new LocationReporter("MobileGPS");
      reporter2.Subscribe(provider);

      provider.TrackLocation(new Location(47.6456, -122.1312));
      reporter1.Unsubscribe();
      provider.TrackLocation(new Location(47.6677, -122.1199));
      provider.TrackLocation(null); // trigger the error condition
      provider.EndTransmission();
    }
  }
}
 

 

 

 

分享到:
评论

相关推荐

    double-dabble:实现Double dabble或shift和add-3算法,以将二进制数转换为Binary-coded Decimal。 使用反向双星号将输出的二进制编码的十进制转换为二进制数。 寄存器编号,移位流程和执行速度应使用5个样本进行测试

    实现Double dabble或shift和add-3算法以将二进制数转换为二进制编码的十进制。 使用反向双星号将输出的二进制编码的十进制转换为二进制数。 寄存器编号,移位流程和执行速度应使用5个样本进行测试SHIFT AND ADD 3...

    chrome-extension-dabble:尝试使用 chrome 扩展程序

    本教程将引导你了解如何创建并使用Chrome扩展程序,特别关注"chrome-extension-dabble"项目。 一、Chrome扩展程序基础 Chrome扩展程序由几个关键组件组成: 1. **manifest.json**:这是扩展程序的配置文件,它...

    Dabble-crx插件

    使用Dabble扩展程序,您可以从任何商店剪辑家具,将它们可视化在一起,并在一个应用程序中跟踪预算! 从任何商店剪辑家具和装饰,将它们一起可视化,并在一个应用程序中跟踪您的预算! 家具购物就像是互联网上的一个...

    使用Dabble控制Arduino的4轮机器人-项目开发

    “4-wheel-robot-made-with-arduino-controlled-using-dabble-4650f7.pdf”很可能是一份项目指南或教程文档,详细介绍了组装4轮机器人和设置Dabble控制的步骤。文档可能包括材料清单、电路图、代码解释和故障排除...

    使用Dabble App的智能手机控制的PC游戏-项目开发

    "smartphone-controlled-pc-game-using-dabble-app-607e65.pdf"很可能包含了项目指南、步骤说明或原理图。这份文档会详细解释如何配置Dabble App,如何编写Arduino代码,以及如何在PC上设置游戏控制器接收和解析...

    Dabble

    【Dabble字体详解】 Dabble是一款独特而富有创意的字体,它以其独特的设计风格和广泛的适用性在字体设计领域中脱颖而出。"Dabble"这个名字本身就带有涂鸦、玩乐的意味,暗示了这款字体轻松、随性的设计理念。设计师...

    dabble-in-java:Java书中的小项目

    在“dabble-in-java:Java书中的小项目”中,我们探索了由Tony Gaddis编著的《从Java入门,早期对象,第三版》一书中的一些实践项目。这个项目集合旨在帮助读者深入理解Java编程语言的核心概念和实战技巧。通过参与...

    JavaScript_3D to Photo是一个由Dabble开发的开源包ejs和Stable diffusi.zip

    ejs通过提供简单的语法,如`&lt;% %&gt;`和`&lt;%= %&gt;`, 让开发者能够轻松地处理数据并将其呈现到页面上。在这个项目中,ejs可能被用来渲染3D模型的预览图或者与用户交互的界面,以便用户可以自定义3D模型的视图和转换设置。 ...

    Stringy:一个多字节支持的字符串操纵类库

    ')-&gt;upper()-&gt;trim(); ``` 这行代码将创建一个字符串对象,然后将其转换为大写并去除两端的空白字符。 4. **类型安全**:Stringy保证了其内部始终处理字符串类型,避免了PHP中字符串与其他类型混合操作可能导致的...

    Z Dabble Down

    "Z Dabble Down" 是一款独特的字体设计,它在IT行业中属于字体艺术的范畴,尤其适用于创意设计、图形用户界面(GUI)以及视觉传达等领域。这款字体以其独特的风格和个性吸引了许多设计师的关注。 首先,我们要了解...

    Binary-to-BCD-Converter:使用双 Dabble Shift 和 Add 3 算法的参数二进制到 BCD 转换器

    ##Parametric Double Dabble Binary to BCD Converter## ##Ameer M. Abdelhadi ( )## ###Parametric Binary to BCD Converter 使用 Double Dabble / Shift 和 Add 3 算法### 平台: DE2-115 Cyclone IV 开发板 ...

    WordPress主题:Dabble v1.5创意代理和投资组合主题2022年最新版.zip

    "WordPress主题:Dabble v1.5创意代理和投资组合主题2022年最新版 WordPress主题/WordPress插件/html网站模板/iOS app源码/安卓app源码 每天更新上传!" ---------- 每天更新发布最新WordPress主题、HTML主题、...

    dabble.me:通过电子邮件服务的私人日记

    Dabble Me会在您选择的时间和日期向您发送电子邮件-您只需回复电子邮件即可发布条目。 该应用程序位于。 如果您曾经使用过则这是一个很好的替代品。 此应用程序利用以下第三者服务: 托管DNS +免费SSL支持(基本...

    赵丽8000口诀总结

    6. `babble` - 胡言乱语,`gabble` - 口齿不清,`dabble` - 涉足,`gobble` - 狼吞虎咽,`nibble` - 小口轻咽。口诀利用谐音和故事将这些动词联系起来,比如“abble 好象 able,baby 胡言乱语”。 7. `tumble` - ...

    外企新自我介绍范文精选.doc

    最后,表达对未来学习和发展的期望,例如:"If I have the opportunity to study in abc University, I’ll dabble in as much as document about the specialty as possible." 这展示了你积极进取的态度和明确的...

    VimeoCast BETA - Chromecast:trade_mark: for Vimeo-crx插件

    轻松投用Vimeo视频(使用vidcast - https://vidcast.dabble.me)到您的Chromecast :trade_mark:/ Android电视设备。 扩展将CAST选项添加到Vimeo视频的上下文菜单(右键单击)。 您必须安装Google Calt Extension。 ...

    VimeoCast测试版 - 适用于Vimeo的Chromecast:trade_mark:「VimeoCast BETA - Chromecast:trade_mark: for Vimeo」-crx插件

    轻松地将Vimeo视频(使用VidCast-https://vidcast.dabble.me)投射到您的Chromecast:trade_mark:/ Android TV设备上。 该扩展程序在Vimeo视频的上下文菜单(右键单击)中添加了投射选项。 您必须安装Google Cast扩展...

    使用Arduino点亮亚克力LED标志-电路方案

    该项目将向您展示如何制作DIY LED...你需要一个亚克力板,一个支架,一个原型板,如Arduino Nano,一个装有Dabble的智能手机,然后就可以开始你的DIY! 您可以从Google Play 下载Dabble 。 点亮3 ... 2 ... 1 ...现在!

    基于智能手机相机制作的循迹机器人-电路方案

    该项目将向您展示如何使用智能手机的相机功能制作循迹机器人。 硬件组件: evive入门套件× 1 ...现在,它的另一个任务是做到循迹,这次用的是智能手机的相机和Dabble,一个智能移动应用程序,以帮助他们协调能力。

Global site tag (gtag.js) - Google Analytics