观察程序设计模式
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了观察程序设计模式,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含52897字,纯文字阅读大概需要76分钟。
内容图文
观察程序设计模式
观察者设计模式使订阅者能够向提供程序注册并接收相关通知。
它适合所有需要推送通知的方案。
</span> (also known as a <span class="parameter">subject</span> or an <span class="parameter">observable</span>) and zero, one, or more <span class="parameter">observers</span>.">该模式定义一个提供程序(也称为主题或观察对象)以及零个、一个或多个观察者。
观察者向提供程序注册,并且当任何预定义的条件、事件或状态更改发生时,提供程序就会调用观察者中的一种方法,自动通知所有观察者。
在此方法调用中,提供程序还可以向观察者提供当前的状态信息。
<span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> and <span><span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interfaces.">在 .NET Framework 中,通过实现泛型 ' ref='nofollow'>System.IObservable
应用模式
观察者设计模式适用于分布式推送通知,因为它支持两种不同的组件或应用程序层之间的绝对分离,例如数据源(业务逻辑)层和用户界面(显示)层。 每当提供程序使用回调向其客户端提供当前信息时,即可实现该模式。
实现该模式需要您提供以下内容:
-
提供程序或主体,即将通知发送给观察者的对象。 <span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface.">提供程序是一个实现 ' ref='nofollow'>IObservable
接口的类或结构。 <span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Subscribe</span></span></span>, which is called by observers that wish to receive notifications from the provider.">提供程序必须实现一个方法 (.Subscribe' ref='nofollow'>IObservable .Subscribe ),希望接收提供程序通知的观察者会调用该方法。 -
观察者,即接收提供程序通知的对象。 <span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface.">观察者是一个实现 ' ref='nofollow'>IObserver
接口的类或结构。 观察者必须实现三个方法,提供程序将调用所有这些方法: -
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnNext</span></span></span>, which supplies the observer with new or current information. "> .OnNext' ref='nofollow'>IObserver
.OnNext ,向观察者提供新信息或当前信息。 -
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnError</span></span></span>, which informs the observer that an error has occurred. "> .OnError' ref='nofollow'>IObserver
.OnError ,通知观察者发生错误。 -
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span>, which indicates that the provider has finished sending notifications."> .OnCompleted' ref='nofollow'>IObserver
.OnCompleted ,指示提供程序已完成通知发送。
-
-
允许提供程序跟踪观察者的机制。 <span class="mtpsTagOuterHtml" ><span>System.Collections.Generic<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> object, to hold references to the <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementations that have subscribed to notifications.">通常情况下,提供程序使用容器对象(例如 ' ref='nofollow'>System.Collections.Generic.List
对象)存放对已订阅通知的 ' ref='nofollow'>IObserver 实现的引用。 因此目的而使用存储容器时,提供程序能够处理零到无限数量的观察者。 不定义观察者接收通知的顺序;提供程序可以自由选择任何方法来确定该顺序。 -
<span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation that enables the provider to remove observers when notification is complete.">允许提供程序在完成通知时移除观察者的 IDisposable 实现。 <span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation from the <span><span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> method, so they can also call the <span><span class="mtpsTagOuterHtml" ><span>IDisposable<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Dispose</span></span></span> method to unsubscribe before the provider has finished sending notifications.">观察者从 Subscribe 方法接收对 IDisposable 实现的引用,所以它们还可以调用 IDisposable.Dispose 方法以在提供程序完成通知发送之前取消订阅。
-
包含提供程序向其观察者发送的数据的对象。 <span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> and <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interfaces.">该对象的类型对应于 ' ref='nofollow'>IObservable
和 ' ref='nofollow'>IObserver 接口的泛型类型参数。 <span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation, most commonly it is a separate type.">尽管该对象可以与 ' ref='nofollow'>IObservable 实现相同,但在通常情况下,该对象为不同的类型。
注意 |
---|
<span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> and <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interfaces.">除实现观察者设计模式外,您可能会对探索使用 ' ref='nofollow'>IObservable |
实现模式
下面的示例使用观察者设计模式实现机场行李提取信息系统。 </span> class provides information about arriving flights and the carousels where baggage from each flight is available for pickup."> BaggageInfo 类提供有关到达航班和提取各次航班行李所用转盘的信息。 如以下示例中所示。
using System; using System.Collections.Generic; publicclass BaggageInfo { privateint flightNo; privatestring origin; privateint location; internal BaggageInfo(int flight, stringfrom, int carousel) { this.flightNo = flight; this.origin = from; this.location = carousel; } publicint FlightNumber { get { returnthis.flightNo; } } publicstring From { get { returnthis.origin; } } publicint Carousel { get { returnthis.location; } } }
</span> class is responsible for receiving information about arriving flights and baggage claim carousels."> BaggageHandler 类负责接收有关到达航班和行李提取转盘的信息。 在内部,它包含两个集合:
-
</span> - A collection of clients that will receive updated information."> observers - 接收更新信息的客户端集合。
-
</span> - A collection of flights and their assigned carousels. "> flights - 航班及其指派的转盘的集合。
<span class="mtpsTagOuterHtml" ><span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> objects that are instantiated in the <span class="code">BaggageHandler</span> class constructor.">两个集合都由 BaggageHandler 类构造函数中实例化的泛型 ' ref='nofollow'>List
public class BaggageHandler : IObservable<BaggageInfo> { private List<IObserver<BaggageInfo>> observers; private List<BaggageInfo> flights; public BaggageHandler() { observers = new List<IObserver<BaggageInfo>>(); flights = new List<BaggageInfo>(); } public IDisposable Subscribe(IObserver<BaggageInfo> observer) { // Check whether observer is already registered. If not, add itif (! observers.Contains(observer)) { observers.Add(observer); // Provide observer with existing data.foreach (var item in flights) observer.OnNext(item); } returnnew Unsubscriber<BaggageInfo>(observers, observer); } // Called to indicate all baggage is now unloaded.publicvoid BaggageStatus(int flightNo) { BaggageStatus(flightNo, String.Empty, 0); } publicvoid BaggageStatus(int flightNo, stringfrom, int carousel) { var info = new BaggageInfo(flightNo, from, carousel); // Carousel is assigned, so add new info object to list.if (carousel > 0 && ! flights.Contains(info)) { flights.Add(info); foreach (var observer in observers) observer.OnNext(info); } elseif (carousel == 0) { // Baggage claim for flight is donevar flightsToRemove = new List<BaggageInfo>(); foreach (var flight in flights) { if (info.FlightNumber == flight.FlightNumber) { flightsToRemove.Add(flight); foreach (var observer in observers) observer.OnNext(info); } } foreach (var flightToRemove in flightsToRemove) flights.Remove(flightToRemove); flightsToRemove.Clear(); } } publicvoid LastBaggageClaimed() { foreach (var observer in observers) observer.OnCompleted(); observers.Clear(); } }
</span> method.">希望接收更新信息的客户端调用 BaggageInfo.Subscribe 方法。
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation is added to the <span class="code">observers</span> collection.">如果客户端之前没有订阅过通知,则会将对客户端 ' ref='nofollow'>IObserver
</span> method can be called to indicate that baggage from a flight either is being unloaded or is no longer being unloaded.">可以调用重载的 BaggageHandler.BaggageStatus 方法以指示是正在卸载还是已卸载航班行李。 在第一种情况中,向该方法传递航班号、航班起飞的机场,以及卸载行李的转盘。 在第二种情况中,仅向该方法传递航班号。 </span> information passed to the method exists in the <span class="code">flights</span> collection.">对于正在卸载的行李,该方法检查传递给方法的 BaggageInfo 信息是否位于 flights 集合中。 </span> method.">如果没有,该方法将添加相应信息并调用每个观察者的 OnNext 方法。 </span> collection.">对于完成行李卸载的航班,该方法会检查有关此航班的信息是否位于 flights 集合中。 </span> method and removes the <span class="code">BaggageInfo</span> object from the <span class="code">flights</span> collection.">如果在该集合中,该方法会调用每个观察者的 OnNext 方法并从 flights 集合中移除 BaggageInfo 对象。
</span> method is called.">当天最后一趟航班着陆并处理完其行李后,将调用 BaggageHandler.LastBaggageClaimed 方法。 </span> method to indicate that all notifications have completed, and then clears the <span class="code">observers</span> collection.">该方法调用每个观察者的 OnCompleted 方法以指示已完成所有通知,然后清除 observers 集合。
<span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> method returns an <span><span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation that enables observers to stop receiving notifications before the <span><span class="mtpsTagOuterHtml" ><span>OnCompleted</span></span></span> method is called.">提供程序的 Subscribe 方法返回使观察者可以在调用 OnCompleted 方法之前停止接收通知的 IDisposable 实现。 (Of BaggageInfo)</span> class is shown in the following example.">下面的示例中显示该 Unsubscriber(Of BaggageInfo) 类的源代码。 </span> method, it is passed a reference to the <span class="code">observers</span> collection and a reference to the observer that is added to the collection.">当类在 BaggageHandler.Subscribe 方法中实例化时,将向其传递对 observers 集合的引用以及对添加至该集合的观察者的引用。 这些引用将指派给局部变量。 </span> method is called, it checks whether the observer still exists in the <span class="code">observers</span> collection, and, if it does, removes the observer.">当调用对象的 Dispose 方法时,它会检查观察者是否仍在 observers 集合中,如果在,则移除观察者。
internal class Unsubscriber<BaggageInfo> : IDisposable { private List<IObserver<BaggageInfo>> _observers; private IObserver<BaggageInfo> _observer; internal Unsubscriber(List<IObserver<BaggageInfo>> observers, IObserver<BaggageInfo> observer) { this._observers = observers; this._observer = observer; } publicvoid Dispose() { if (_observers.Contains(_observer)) _observers.Remove(_observer); } }
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation named <span class="code">ArrivalsMonitor</span>, which is a base class that displays baggage claim information.">下面的示例提供名为 ArrivalsMonitor 的 ' ref='nofollow'>IObserver
using System; using System.Collections.Generic; publicclass ArrivalsMonitor : IObserver<BaggageInfo> { privatestring name; private List<string> flightInfos = new List<string>(); private IDisposable cancellation; privatestring fmt = "{0,-20} {1,5} {2, 3}"; public ArrivalsMonitor(string name) { if (String.IsNullOrEmpty(name)) thrownew ArgumentNullException("The observer must be assigned a name."); this.name = name; } publicvirtualvoid Subscribe(BaggageHandler provider) { cancellation = provider.Subscribe(this); } publicvirtualvoid Unsubscribe() { cancellation.Dispose(); flightInfos.Clear(); } publicvirtualvoid OnCompleted() { flightInfos.Clear(); } // No implementation needed: Method is not called by the BaggageHandler class.publicvirtualvoid OnError(Exception e) { // No implementation. } // Update information.publicvirtualvoid OnNext(BaggageInfo info) { bool updated = false; // Flight has unloaded its baggage; remove from the monitor.if (info.Carousel == 0) { var flightsToRemove = new List<string>(); string flightNo = String.Format("{0,5}", info.FlightNumber); foreach (var flightInfo in flightInfos) { if (flightInfo.Substring(21, 5).Equals(flightNo)) { flightsToRemove.Add(flightInfo); updated = true; } } foreach (var flightToRemove in flightsToRemove) flightInfos.Remove(flightToRemove); flightsToRemove.Clear(); } else { // Add flight if it does not exist in the collection.string flightInfo = String.Format(fmt, info.From, info.FlightNumber, info.Carousel); if (! flightInfos.Contains(flightInfo)) { flightInfos.Add(flightInfo); updated = true; } } if (updated) { flightInfos.Sort(); Console.WriteLine("Arrivals information from {0}", this.name); foreach (var flightInfo in flightInfos) Console.WriteLine(flightInfo); Console.WriteLine(); } } }
</span> class includes the <span class="code">Subscribe</span> and <span class="code">Unsubscribe</span> methods."> ArrivalsMonitor 类包括 Subscribe 和 Unsubscribe 方法。
</span> method enables the class to save the <span><span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation returned by the call to <span><span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> to a private variable."> Subscribe 方法允许类将由对 Subscribe 的调用返回的 IDisposable 实现保存至私有变量中。
</span> method enables the class to unsubscribe from notifications by calling the provider‘s <span><span class="mtpsTagOuterHtml" ><span>Dispose</span></span></span> implementation."> Unsubscribe 方法允许类通过调用提供程序的 Dispose 实现来取消订阅通知。
</span> also provides implementations of the <span><span class="mtpsTagOuterHtml" ><span>OnNext</span></span></span>, <span><span class="mtpsTagOuterHtml" ><span>OnError</span></span></span>, and <span><span class="mtpsTagOuterHtml" ><span>OnCompleted</span></span></span> methods."> ArrivalsMonitor 还提供 OnNext、OnError 和 OnCompleted 方法的实现。
<span class="mtpsTagOuterHtml" ><span>OnNext</span></span></span> implementation contains a significant amount of code.">仅 OnNext 实现包含大量代码。
<span class="mtpsTagOuterHtml" ><span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> object that maintains information about the airports of origin for arriving flights and the carousels on which their baggage is available.">该方法使用已排序的私有泛型 ' ref='nofollow'>List
</span> class as well as two instances of the <span class="code">ArrivalsMonitor</span> class, and uses the <span class="code">BaggageHandler.BaggageStatus</span> method to add and remove information about arriving flights.">下面的示例包含实例化 BaggageHandler 类的应用程序入口点,以及两个 ArrivalsMonitor 类的实例,并使用 BaggageHandler.BaggageStatus 方法添加和移除有关到达航班的信息。 在每种情况下,观察者都接收更新并正确显示行李提取信息。
using System; using System.Collections.Generic; publicclass Example { publicstaticvoid Main() { BaggageHandler provider = new BaggageHandler(); ArrivalsMonitor observer1 = new ArrivalsMonitor("BaggageClaimMonitor1"); ArrivalsMonitor observer2 = new ArrivalsMonitor("SecurityExit"); provider.BaggageStatus(712, "Detroit", 3); observer1.Subscribe(provider); provider.BaggageStatus(712, "Kalamazoo", 3); provider.BaggageStatus(400, "New York-Kennedy", 1); provider.BaggageStatus(712, "Detroit", 3); observer2.Subscribe(provider); provider.BaggageStatus(511, "San Francisco", 2); provider.BaggageStatus(712); observer2.Unsubscribe(); provider.BaggageStatus(400); provider.LastBaggageClaimed(); } } // The example displays the following output:// Arrivals information from BaggageClaimMonitor1// Detroit 712 3//// Arrivals information from BaggageClaimMonitor1// Detroit 712 3// Kalamazoo 712 3//// Arrivals information from BaggageClaimMonitor1// Detroit 712 3// Kalamazoo 712 3// New York-Kennedy 400 1//// Arrivals information from SecurityExit// Detroit 712 3//// Arrivals information from SecurityExit// Detroit 712 3// Kalamazoo 712 3//// Arrivals information from SecurityExit// Detroit 712 3// Kalamazoo 712 3// New York-Kennedy 400 1//// Arrivals information from BaggageClaimMonitor1// Detroit 712 3// Kalamazoo 712 3// New York-Kennedy 400 1// San Francisco 511 2//// Arrivals information from SecurityExit// Detroit 712 3// Kalamazoo 712 3// New York-Kennedy 400 1// San Francisco 511 2//// Arrivals information from BaggageClaimMonitor1// New York-Kennedy 400 1// San Francisco 511 2//// Arrivals information from SecurityExit// New York-Kennedy 400 1// San Francisco 511 2//// Arrivals information from BaggageClaimMonitor1// San Francisco 511 2
观察程序设计模式最佳做法
在 .NET Framework 中,以一组接口的形式实现观察者设计模式。
<span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface represents the data provider, which is also responsible for providing an <span><span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation that lets observers unsubscribe from notifications."> ' ref='nofollow'>System.IObserver
线程处理
<span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Subscribe</span></span></span> method by adding a particular observer to a subscriber list that is represented by some collection object, and it implements the <span><span class="mtpsTagOuterHtml" ><span>IDisposable<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Dispose</span></span></span> method by removing a particular observer from the subscriber list.">通常,提供程序通过将特定的观察者添加到由某些集合对象表示的订阅者列表中来实现 .Subscribe' ref='nofollow'>IObservable
除提供程序/观察者协定外,还必须在层中指定任何其他保证。 当实施者强加其他要求时应进行明确说明,以避免用户对观察者协定产生混淆。
处理异常
由于数据提供程序和观察者之间存在松耦合,因此观察者设计模式中的异常主要用于提供信息。 这会影响提供程序和观察者在观察者设计模式中处理异常的方式。
提供程序 -- 调用 OnError 方法
<span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method is intended as an informational message to observers, much like the <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnNext</span></span></span> method."> OnError 方法旨在为观察者提供信息性消息,它与 .OnNext' ref='nofollow'>IObserver
<span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method:">提供程序在处理异常和调用 OnError 方法时应遵循以下最佳做法:
-
如果提供程序具有任何特定的要求,则必须处理自己的异常。
-
提供程序不应期待或要求观察者以任何特殊的方式处理异常。
-
<span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method when it handles an exception that compromises its ability to provide updates.">当提供程序处理有损其更新提供能力的异常时,应调用 OnError 方法。 可将此类异常的信息传递给观察者。 在其他情况下,则无需向观察者通知异常。
<span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> or <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span> method, there should be no further notifications, and the provider can unsubscribe its observers.">提供程序调用 OnError 或 .OnCompleted' ref='nofollow'>IObserver
观察者 -- 实现 OnError 方法
当观察者收到来自提供程序的错误通知时,观察者应将异常作为信息处理,并且不应被要求执行任何特殊的操作。
<span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method call from a provider:">观察者在响应来自提供程序的 OnError 方法调用时应遵循以下最佳做法:
-
<span class="mtpsTagOuterHtml" ><span>OnNext</span></span></span> or <span><span class="mtpsTagOuterHtml" ><span>OnError</span></span></span>.">观察者不应从其接口实现引发异常,例如 OnNext 或 OnError。 但是,如果观察者确实引发了异常,则应期望这些异常处于未处理状态。
-
<span class="mtpsTagOuterHtml" ><span>Exception</span></span></span> object that was passed to its <span><span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method should wrap the exception before throwing it.">若要保留调用堆栈,希望引发传递给其 OnError 方法的 Exception 对象的观察者,应在引发之前对异常进行包装。 为此,应使用标准异常对象。
其他最佳做法
<span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Subscribe</span></span></span> method may result in a null reference.">在 .Subscribe' ref='nofollow'>IObservable
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> instance to only one <span><span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> instance. ">尽管可以将一个观察者附加到多个提供程序,但建议的模式是将一个 ' ref='nofollow'>IObserver
如何:实现提供程序
观察者设计模式要求在提供程序(监视数据和发送通知)和一个或多个观察者(接收提供程序的通知,即回调)之间进行区分。 本主题讨论如何创建提供程序。 <span class="mtpsTagOuterHtml" ><span>How to: Implement an Observer</span></span></span>, discusses how to create an observer.">相关主题如何:实现观察程序讨论如何创建观察者。
创建提供程序
-
定义提供程序负责发送给观察者的数据。 尽管提供程序和它发送给观察者的数据可以为一个类型,但是通常它们都采用不同的类型表示。 </span> structure defines the data that the provider (which is represented by the <span class="code">TemperatureMonitor</span> class defined in the next step) monitors and to which observers subscribe.">例如,在温度监控应用程序中,Temperature 结构定义提供程序(由下一步中定义的 TemperatureMonitor 类表示)监控的数据和观察者订阅的数据。
using System; publicstruct Temperature { privatedecimal temp; private DateTime tempDate; public Temperature(decimal temperature, DateTime dateAndTime) { this.temp = temperature; this.tempDate = dateAndTime; } publicdecimal Degrees { get { returnthis.temp; } } public DateTime Date { get { returnthis.tempDate; } } }
-
<span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface.">定义数据提供程序,这是实现 ' ref='nofollow'>System.IObservable
接口的类型。 提供程序的泛型类型参数是提供程序发送给观察者的类型。 </span> class, which is a constructed <span><span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation with a generic type argument of <span class="code">Temperature</span>.">下面的示例定义了一个 TemperatureMonitor 类,它是具有 Temperature 泛型类型参数的构造 ' ref='nofollow'>System.IObservable 实现。 using System; using System.Collections.Generic; publicclass TemperatureMonitor : IObservable<Temperature> { ... }
-
确定提供程序存储观察者引用的方式,以便每个观察者都能在适当的时候得到通知。 <span class="mtpsTagOuterHtml" ><span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> object is used for this purpose.">最常用于此目的是集合对象,如泛型 ' ref='nofollow'>List
对象。 <span class="mtpsTagOuterHtml" ><span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> object that is instantiated in the <span class="code">TemperatureMonitor</span> class constructor.">下面的示例定义了一个专用的 ' ref='nofollow'>List 对象,它在 TemperatureMonitor 类构造函数中实例化。 using System; using System.Collections.Generic; publicclass TemperatureMonitor : IObservable<Temperature> { List<IObserver<Temperature>> observers; public TemperatureMonitor() { observers = new List<IObserver<Temperature>>(); } ... }
-
<span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation that the provider can return to subscribers so that they can stop receiving notifications at any time.">定义提供程序可以返回至订阅者的 IDisposable 实现,以便它们能够随时停止接收通知。 </span> class that is passed a reference to the subscribers collection and to the subscriber when the class is instantiated.">下面的示例定义了一个嵌套的 Unsubscriber 类,在实例化类时,会向该类传递对订阅者集合和订阅者的引用。 <span class="mtpsTagOuterHtml" ><span>IDisposable<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Dispose</span></span></span> implementation to remove itself from the subscribers collection.">此代码允许订阅者调用对象的 IDisposable.Dispose 实现,以将其自身从订阅者集合中移除。
private class Unsubscriber : IDisposable { private List<IObserver<Temperature>> _observers; private IObserver<Temperature> _observer; public Unsubscriber(List<IObserver<Temperature>> observers, IObserver<Temperature> observer) { this._observers = observers; this._observer = observer; } publicvoid Dispose() { if (! (_observer == null)) _observers.Remove(_observer); } }
-
<span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Subscribe</span></span></span> method.">实现 .Subscribe' ref='nofollow'>IObservable
.Subscribe 方法。 <span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface and should be stored in the object designed for that purpose in step 3.">将向该方法传递对 ' ref='nofollow'>System.IObserver接口的引用,并且该方法应存储在步骤 3 中为该目的而设计的对象中。 <span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation developed in step 4.">然后,该方法应该返回步骤 4 中开发的 IDisposable 实现。 <span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> method in the <span class="code">TemperatureMonitor</span> class.">下面的示例演示 TemperatureMonitor 类中 Subscribe 方法的实现。 public IDisposable Subscribe(IObserver<Temperature> observer) { if (! observers.Contains(observer)) observers.Add(observer); returnnew Unsubscriber(observers, observer); }
-
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnNext</span></span></span>, <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnError</span></span></span>, and <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span> implementations.">通过调用观察者的 .OnNext' ref='nofollow'>IObserver
.OnNext 、.OnError' ref='nofollow'>IObserver.OnError 和 .OnCompleted' ref='nofollow'>IObserver.OnCompleted 实现,根据需要通知观察者。 <span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method when an error occurs.">在某些情况下,提供程序在发生错误时可能不会调用 OnError 方法。 </span> method simulates a monitor that reads temperature data every five seconds and notifies observers if the temperature has changed by at least .1 degree since the previous reading.">例如,下面的 GetTemperature 方法模拟一个监视器,它每五秒读取一次温度数据,并对照之前的读数,如果温度的变化大于或等于 0.1 度则通知观察者。 如果设备不报告温度(即其值为 null),则提供程序会通知观察者传输已完成。 <span class="mtpsTagOuterHtml" ><span>OnCompleted</span></span></span> method, the <span class="code">GetTemperature</span> method clears the <span><span class="mtpsTagOuterHtml" ><span>List<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> collection.">请注意,除调用每个观察者的 OnCompleted 方法外,GetTemperature 方法还会清除 ' ref='nofollow'>List集合。 <span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method of its observers.">在这种情况下,提供程序不调用其观察者的 OnError 方法。 public void GetTemperature() { // Create an array of sample data to mimic a temperature device. Nullable<Decimal>[] temps = {14.6m, 14.65m, 14.7m, 14.9m, 14.9m, 15.2m, 15.25m, 15.2m, 15.4m, 15.45m, null }; // Store the previous temperature, so notification is only sent after at least .1 change. Nullable<Decimal> previous = null; bool start = true; foreach (var temp in temps) { System.Threading.Thread.Sleep(2500); if (temp.HasValue) { if (start || (Math.Abs(temp.Value - previous.Value) >= 0.1m )) { Temperature tempData = new Temperature(temp.Value, DateTime.Now); foreach (var observer in observers) observer.OnNext(tempData); previous = temp; if (start) start = false; } } else { foreach (var observer in observers.ToArray()) if (observer != null) observer.OnCompleted(); observers.Clear(); break; } } }
示例
<span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation for a temperature monitoring application.">下面的示例包含定义温度监控应用程序的 ' ref='nofollow'>IObservable
using System.Threading; using System; using System.Collections.Generic; publicclass TemperatureMonitor : IObservable<Temperature> { List<IObserver<Temperature>> observers; public TemperatureMonitor() { observers = new List<IObserver<Temperature>>(); } privateclass Unsubscriber : IDisposable { private List<IObserver<Temperature>> _observers; private IObserver<Temperature> _observer; public Unsubscriber(List<IObserver<Temperature>> observers, IObserver<Temperature> observer) { this._observers = observers; this._observer = observer; } publicvoid Dispose() { if (! (_observer == null)) _observers.Remove(_observer); } } public IDisposable Subscribe(IObserver<Temperature> observer) { if (! observers.Contains(observer)) observers.Add(observer); returnnew Unsubscriber(observers, observer); } publicvoid GetTemperature() { // Create an array of sample data to mimic a temperature device. Nullable<Decimal>[] temps = {14.6m, 14.65m, 14.7m, 14.9m, 14.9m, 15.2m, 15.25m, 15.2m, 15.4m, 15.45m, null }; // Store the previous temperature, so notification is only sent after at least .1 change. Nullable<Decimal> previous = null; bool start = true; foreach (var temp in temps) { System.Threading.Thread.Sleep(2500); if (temp.HasValue) { if (start || (Math.Abs(temp.Value - previous.Value) >= 0.1m )) { Temperature tempData = new Temperature(temp.Value, DateTime.Now); foreach (var observer in observers) observer.OnNext(tempData); previous = temp; if (start) start = false; } } else { foreach (var observer in observers.ToArray()) if (observer != null) observer.OnCompleted(); observers.Clear(); break; } } } }
如何:实现观察程序
观察者设计模式要求在观察者(注册通知)和提供程序(监视数据并将通知发送至一个或多个观察者)之间插入分隔符。 本主题讨论如何创建观察者。 <span class="mtpsTagOuterHtml" ><span>How to: Implement a Provider</span></span></span>, discusses how to create an provider.">相关主题如何:实现提供程序讨论如何创建提供程序。
创建观察者
-
<span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface.">定义作为实现 ' ref='nofollow'>System.IObserver
接口的类型的观察者。 </span> that is a constructed <span><span class="mtpsTagOuterHtml" ><span>System<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation with a generic type argument of <span class="code">Temperature</span>.">例如,下面的代码定义一个名为 TemperatureReporter 的类型,它是使用 Temperature 泛型类型参数构造的 ' ref='nofollow'>System.IObserver 实现。 public class TemperatureReporter : IObserver<Temperature>
-
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span> implementation, define a private variable that will hold the <span><span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> implementation returned by the provider‘s <span><span class="mtpsTagOuterHtml" ><span>IObservable<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Subscribe</span></span></span> method.">如果观察者可以在提供程序调用其 .OnCompleted' ref='nofollow'>IObserver
.OnCompleted 实现之前停止接收通知,请定义保留提供程序的 .Subscribe' ref='nofollow'>IObservable.Subscribe 方法返回的 IDisposable 实现的私有变量。 <span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> method and stores the returned <span><span class="mtpsTagOuterHtml" ><span>IDisposable</span></span></span> object.">还应定义调用提供程序的 Subscribe 方法并存储返回的 IDisposable 对象的订阅方法。 </span> and defines a <span class="code">Subscribe</span> method that calls the provider‘s <span><span class="mtpsTagOuterHtml" ><span>Subscribe</span></span></span> method and assigns the returned object to the <span class="code">unsubscriber</span> variable.">例如,下面的代码定义一个名为 unsubscriber 的私有变量,并定义一个调用提供程序的 Subscribe 方法并将返回的对象指派给 unsubscriber 变量的 Subscribe 方法。public class TemperatureReporter : IObserver<Temperature> { private IDisposable unsubscriber; privatebool first = true; private Temperature last; publicvirtualvoid Subscribe(IObservable<Temperature> provider) { unsubscriber = provider.Subscribe(this); } ... }
-
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span> implementation, if this feature is required.">定义使观察者可以在提供程序调用其 .OnCompleted' ref='nofollow'>IObserver
.OnCompleted 实现之前停止接收通知的方法(如果需要此功能)。 </span> method.">下面的示例定义 Unsubscribe 方法。public virtual void Unsubscribe() { unsubscriber.Dispose(); }
-
<span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> interface: <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnNext</span></span></span>, <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnError</span></span></span>, and <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span><span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>OnCompleted</span></span></span>.">提供由 ' ref='nofollow'>IObserver
接口定义的三种方法的实现:.OnNext' ref='nofollow'>IObserver .OnNext 、.OnError' ref='nofollow'>IObserver.OnError 和 .OnCompleted' ref='nofollow'>IObserver.OnCompleted 。 <span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> and <span><span class="mtpsTagOuterHtml" ><span>OnCompleted</span></span></span> methods can be stub implementations.">根据提供程序和应用程序的需求,OnError 和 OnCompleted 方法可以为存根实现。 <span class="mtpsTagOuterHtml" ><span>OnError</span></span></span> method should not handle the passed <span><span class="mtpsTagOuterHtml" ><span>Exception</span></span></span> object as an exception, and the <span><span class="mtpsTagOuterHtml" ><span>OnCompleted</span></span></span> method is free to call the provider‘s <span><span class="mtpsTagOuterHtml" ><span>IDisposable<span class="mtpsTagOuterHtml" xmlns=""><span>.</span></span>Dispose</span></span></span> implementation.">注意,OnError 方法不应将传递的 Exception 对象作为异常处理,而 OnCompleted 方法可以自由调用提供程序的 IDisposable.Dispose 实现。 <span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation of the <span class="code">TemperatureReporter</span> class.">下面的示例演示 TemperatureReporter 类的 ' ref='nofollow'>IObserver实现。 public virtual void OnCompleted() { Console.WriteLine("Additional temperature data will not be transmitted."); } publicvirtualvoid OnError(Exception error) { // Do nothing. } publicvirtualvoid OnNext(Temperature value) { Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date); if (first) { last = value; first = false; } else { Console.WriteLine(" Change: {0}° in {1:g}", value.Degrees - last.Degrees, value.Date.ToUniversalTime() - last.Date.ToUniversalTime()); } }
示例
</span> class, which provides the <span><span class="mtpsTagOuterHtml" ><span>IObserver<span class="mtpsTagOuterHtml" xmlns=""><span><</span></span>T<span class="mtpsTagOuterHtml" xmlns=""><span>></span></span></span></span></span> implementation for a temperature monitoring application. ">下面的示例包含 TemperatureReporter 类(提供温度监控应用程序的 ' ref='nofollow'>IObserver
public class TemperatureReporter : IObserver<Temperature> { private IDisposable unsubscriber; privatebool first = true; private Temperature last; publicvirtualvoid Subscribe(IObservable<Temperature> provider) { unsubscriber = provider.Subscribe(this); } publicvirtualvoid Unsubscribe() { unsubscriber.Dispose(); } publicvirtualvoid OnCompleted() { Console.WriteLine("Additional temperature data will not be transmitted."); } publicvirtualvoid OnError(Exception error) { // Do nothing. } publicvirtualvoid OnNext(Temperature value) { Console.WriteLine("The temperature is {0}°C at {1:g}", value.Degrees, value.Date); if (first) { last = value; first = false; } else { Console.WriteLine(" Change: {0}° in {1:g}", value.Degrees - last.Degrees, value.Date.ToUniversalTime() - last.Date.ToUniversalTime()); } } }
原文:http://www.cnblogs.com/go-jzg/p/6388880.html
内容总结
以上是互联网集市为您收集整理的观察程序设计模式全部内容,希望文章能够帮你解决观察程序设计模式所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。