patterncsharpMinor
Local (In-Process) Publish/Subscribe
Viewed 0 times
publishlocalsubscribeprocess
Problem
I have a handful of objects that don't have references to each-other that all need to receive an update.
From what I've read, it seems like a Publish-Subscribe Messaging Channel is an appropriate pattern. Searching for an existing solution mainly turned up messaging libraries for application integration (between processes). Those solutions were much more than what I needed, so I wrote this simple Publisher.
Questions:
```
public interface ISubscriber
{
void SubscriptionUpdate(object message);
}
public interface IPublisher
{
void Subscribe(ISubscriber subscriber, string channel);
void Unsubscribe(ISubscriber subscriber, string channel);
void Publish(string channel, object message);
}
public class Publisher : IPublisher
{
static Publisher _instance = new Publisher();
public static Publisher Instance { get { return _instance; } }
Dictionary> _subscribers = new Dictionary>();
public void Subscribe(ISubscriber subscriber, string channel)
{
if (!Exists(channel))
_subscribers[channel] = new List();
if (!_subscribers[channel].Contains(subscriber))
_subscribers[channel].Add(subscriber);
}
public void Unsubscribe(ISubscriber subscriber, string channel)
{
if (Exists(channel))
_subscribers[channel].Remove(subscriber);
}
public void Publish(string channel, object message)
{
if (!Exists(channel)) return;
foreach (var subscriber in _subscribers[channel])
subscriber.SubscriptionUpdate(message);
}
bool Exists(string channel)
{
return _subscribers.ContainsKey(channel);
}
}
From what I've read, it seems like a Publish-Subscribe Messaging Channel is an appropriate pattern. Searching for an existing solution mainly turned up messaging libraries for application integration (between processes). Those solutions were much more than what I needed, so I wrote this simple Publisher.
Questions:
- Is there already something simple like this in the .NET framework that I overlooked? Or another light-weight library?
- Is this an appropriate implementation and application of the Pub/Sub pattern? What might be done to improve it?
- What gotchas are there? For example, I presume I need to Unsubscribe in the subscriber's finalizer.
```
public interface ISubscriber
{
void SubscriptionUpdate(object message);
}
public interface IPublisher
{
void Subscribe(ISubscriber subscriber, string channel);
void Unsubscribe(ISubscriber subscriber, string channel);
void Publish(string channel, object message);
}
public class Publisher : IPublisher
{
static Publisher _instance = new Publisher();
public static Publisher Instance { get { return _instance; } }
Dictionary> _subscribers = new Dictionary>();
public void Subscribe(ISubscriber subscriber, string channel)
{
if (!Exists(channel))
_subscribers[channel] = new List();
if (!_subscribers[channel].Contains(subscriber))
_subscribers[channel].Add(subscriber);
}
public void Unsubscribe(ISubscriber subscriber, string channel)
{
if (Exists(channel))
_subscribers[channel].Remove(subscriber);
}
public void Publish(string channel, object message)
{
if (!Exists(channel)) return;
foreach (var subscriber in _subscribers[channel])
subscriber.SubscriptionUpdate(message);
}
bool Exists(string channel)
{
return _subscribers.ContainsKey(channel);
}
}
Solution
Update (2022): If you do want to use an in-process publish-subscribe pattern - consider using a very popular package MediatR. Events are kind of a legacy approach now.
Original answer (2013):
Don't think it's a good approach.
.NET already has a notion of in-process publish/subscribe, and (not that surprisingly) this functionality is covered by events... All you need to do is to wire up all your entities properly, and that's your actual challenge is.
I would recommend using any of available IoC frameworks for that (I use Autofac at the moment).
Unfortunately you haven't described specific use cases for your pub/sub requirement so it's hard to show this solution on specific example
Original answer (2013):
Don't think it's a good approach.
- Singletons are evil by themselves
- Subscribers are likely to expect a specific type of message on specific channel
- Magic strings that specify the channel name are also potential source of bugs
- Incorrect messages or posts to wrong channels are detected at run-time only.
- Logical dependency between objects still exist, but is hidden.
.NET already has a notion of in-process publish/subscribe, and (not that surprisingly) this functionality is covered by events... All you need to do is to wire up all your entities properly, and that's your actual challenge is.
I would recommend using any of available IoC frameworks for that (I use Autofac at the moment).
- You will have a strictly-typed communication protocol between publisher and subscriber
- It will allow you to explicitly declare dependency on a certain external functionality in your classes.
- It will simplify unit-testing of your classes
Unfortunately you haven't described specific use cases for your pub/sub requirement so it's hard to show this solution on specific example
Context
StackExchange Code Review Q#26730, answer score: 2
Revisions (0)
No revisions yet.