VIPリスナーパターン

率直に言って、私はこのパターンの説明を見たことがないので、その名前を発明しました。 誰かが正しい名前についての情報を持っているなら、私は聞いてとてもうれしいです。 パターンは言語に関連付けられていませんが、この記事ではC#を使用します。

注目を集める画像:




したがって、オブジェクトのセットを追跡するシステムの他の部分を提供するサービスで構成されるシステムを想像してください。 シミュレートされたオブジェクトまたはその他の類似したオブジェクトのリストを提供するシミュレーションサービスにすることができます。

システムによって生成および破棄されるオブジェクト:
  public interface IObject { } 


オブジェクトへのアクセスを提供するサービス:
  public delegate void ServiceChangedHandle(IService sender, IObject item, bool injected); public interface IService { IEnumerable<IObject> Items { get; } event ServiceChangedHandle OnServiceChanged; } 


オブジェクトを操作する必要があるシステムは、新しいオブジェクトの出現と現在のオブジェクトの消失を追跡するためにイベントにサブスクライブされます。

典型的なリスナーの例:
  public class Listener { public void Initialise() { foreach (var item in service.Items) RegisterItem(item); service.OnServiceChanged += OnServiceChanged; } public void Shutdown() { service.OnServiceChanged -= OnServiceChanged; foreach (var item in service.Items) UnregisterItem(item); } private void OnServiceChanged(IService sender, IObject item, bool injected) { if (injected) RegisterItem(item); else UnregisterItem(item); } private void RegisterItem(IObject item) { ... } private void UnregisterItem(IObject item) { ... } private IService service; } 


リスナーがアクティブ化されると、サービス内にすでに存在するすべてのオブジェクトを処理し、その後、オブジェクトのリストの変更をサブスクライブします。 リスナーの作業が完了したら、逆のアクションを実行する必要があります。
マルチスレッドプログラミングでは、ポーリングとサブスクライブの間でオブジェクトのリストが変わる可能性があるため、事態は複雑になります。 サービスは同期オブジェクトを提供する必要があり、リスナーはリストのクロールとサブスクリプションの間のリストの変更をブロックします。

マルチスレッドをサポートするサービス:
  public interface IService { ... //    object SyncRoot { get; } } 


マルチスレッドサービスをサポートするリスナー(内部同期は省略):
  public class Listener { public void Initialise() { //   lock (service.SyncRoot) { foreach (var item in service.Items) RegisterItem(item); service.OnServiceChanged += OnServiceChanged; } } public void Shutdown() { //   lock (service.SyncRoot) { service.OnServiceChanged -= OnServiceChanged; foreach (var item in service.Items) UnregisterItem(item); } } ... } 


サブスクリプションおよびサブスクリプション解除時にサービスにオブジェクトが存在しないことを保証する場合、サブスクリプションシステムを少し簡素化できます。 特にサービスの出現時間が定義されていないシステムでは、このような保証を与えることは困難です。
しかし、各加入者に対してこの保証をエミュレートできます。これがパターンの本質です。 サブスクライブするとき、サービスは既存のすべてのオブジェクトのオブジェクト出現イベントを強制的に送信し、サブスクライブ解除するとき、消滅イベントを送信します。 同時に、リスナーは単純化されており、マルチスレッド版とシングルスレッド版では同じように見えます。

マルチスレッドおよびシングルスレッドサービスオプションのサブスクライバー(内部同期は省略):
  public class Listener { public void Initialise() { service.OnServiceChanged += OnServiceChanged; } public void Shutdown() { service.OnServiceChanged -= OnServiceChanged; } ... } 


シングルスレッドバージョンのサービス実装:
  public class Service : IService { ... public event ServiceChangedHandle OnServiceChanged { add { //      foreach (var item in items) value(this, item, true); //   eventHandle += value; } remove { //   eventHandle -= value; //    foreach (var item in items) value(this, item, false); } } private ServiceChangedHandle eventHandle; private List<IObject> items = new List<IObject>(); } 


他のパターンと同様に、このバージョンのリスナーには長所、短所、スコープがあります。

長所:


短所:


マイナスとプラスから、パターンの範囲を区別できます。


Update1
いくつかの説明:
「オブザーバー」パターンは既に鋭く実装されており、オブザーバーとオブザーバーの代わりに、イベントとサブスクライバーがあります。
VIPは「1」という言葉の同義語ではなく、「特別」という言葉の同義語です。 この場合、監視対象オブジェクトは個々の監視者ごとに異なる動作をするため、すべてのサブスクライバは特別です。 つまり、オブザーバがスキップしたり待機したりできないイベントを生成します。

ご清聴ありがとうございました!

Source: https://habr.com/ru/post/J201908/


All Articles