Day 10 – Global values in a program

When you create a program you properly have a lot of values (or just a few) which must be readable at all times to the system’s different parts.
Also there can be values you don’t care about – they just need to live on.

In my case my GUI has a region which only knows if the motor is activated or deactivated. It does not care of how fast it runs or which direction it spins. And at all times it must be aware of the state.
Therefore it’s no use to me only to send an event to update it – it must know when it wants to.
How to do that – here’s my idea:

Create a singleton in the Infrastructure:

public class GlobalValues : IGlobalValues
{
	private readonly IEventAggregator _eventAggregator;
	private static GlobalValues _instance;
	public static GlobalValues Instance
	{
		get
		{
			if(_instance == null)
				throw new Exception("GlobalValues has not been created");
			return _instance;
		}
	}

   public static void Create(IEventAggregator eventAggregator)
	{
		if(_instance == null)
			_instance = new GlobalValues(eventAggregator);
	}

	private GlobalValues(IEventAggregator eventAggregator)
	{
		_eventAggregator = eventAggregator;
	}
	...
	...
}

Perhaps you notice that this isn’t a normal singleton. This takes in a parameter, IEventAggregator, since I want to subscribe to different types of events. I will show these later.

If you did not use an IOC Container (Unity, here) you could get the singleton object with code like this:

var obj = GlobalValues.Instance;

It would create the singleton the first time you were to use it and take the instance the following calls.
But we have a speciel case here – We want a parameter within it, IEventAggregator, and since we do not want to specify that every time we start it up here’s what we are going to do:

In the Infrastructure’s Module-class register GlobalValues as following:

public void Initialize()
{
  GlobalValues.Create(_container.Resolve<EventAggregator>());
  var singleton = GlobalValues.Instance;
  _container.RegisterInstance<IGlobalValues>(singleton);
  ...
}

First we create the singleton with its parameter, the we get the instance and register it with an interface (which is empty right now…).

Now the call we need to do to get the instance will look like this:

var obj = _container.Resolve<IGlobalValues>();

What now? We got a singleton but no data. And the data must be available in all instances of the interface IGlobalValues.

So, example – the following is data representing my motor.
Since I have them in an interface a concrete class can derive from it – or another interface could.

public interface IMotor
{
	bool Activated { get; }
	int Speed { get; }
	RotationDirection Rotation { get; }
}

public interface IGlobalValues : IMotor
{}

With this the class which derive from IGlobalValues must also implement IMotor’s members.
This adds the following to GlobalValues:

public class GlobalValues : IGlobalValues
{
    ...
	public bool Activated { get; private set; }
	public int Speed { get; private set; }
	public RotationDirection Rotation { get; private set; }
}

Funny thing to notice: the three properties now has a private setter – they did not have that originally.
This is done because I do not want other classes to update the GlobalValues without everyone gets to know of it.

How to set the values then – with the EventAggregator:

private void SubscribeToEvents()
{
	var activateMotorEvent = _eventAggregator
             .GetEvent<UpdateMotorEvent>();

	if (subscriptionToken != null)
	{
		activateMotorEvent.Unsubscribe(subscriptionToken);
	}

	subscriptionToken = activateMotorEvent
                   .Subscribe(UpdateMotorHandler, 
                              ThreadOption.BackgroundThread, 
                              false);
}

private void UpdateMotorHandler(Motor obj)
{
	Speed = obj.Speed;
	Activated = obj.Activated;
	Rotation = obj.Rotation;
}

This means, that if you want to update the motor with new values they are set in the GlobalValues as well, they can always be reached in your program and they won’t differ from the actual values.

What if I only want to update 1 of the values?
Pff – take a copy of GlobalValues, update your value and publish it:

public class Motor : IMotor
{
	private readonly IUnityContainer _container;

	public Motor(IUnityContainer container)
	{
		_container = container;
		Activated = _container.Resolve<IGlobalValues>().Activated;
		Rotation = _container.Resolve<IGlobalValues>().Rotation;
		Speed = _container.Resolve<IGlobalValues>().Speed;
	}

	public bool Activated { set; get; }
	public int Speed { set; get; }
	public RotationDirection Rotation { set; get; }
}

public class SomeRegion
{
	private void StartCommandExecute()
	{
		var motor = _container.Resolve<Motor>();
		motor.Activated = true;

		_eventAggregator.GetEvent<UpdateMotorEvent>().Publish(motor);
	}
}

I am positive that there are a better way to do this.
But for now it works fine

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>