Search code examples
c#design-patternsruntimefactory-pattern

Design patterns for runtime object creation


I have a class which facilitates the discovery of HID devices, when a device is detected an event is raised and subsequently detected by another class which will be ultimately responsible for the creation of an object to represent the HID device. The creation class raises an event of its own with the newly created HID object.

With this in mind I have a couple of design queries:

1) I have done some research into the "best practices" with regards to the creation of an unknown number or type of object at runtime for which the Abstract Factory design pattern features frequently in the results. Does the Abstract Factory design pattern fit the scenario I have, or is there something else I should be doing?

2) The HidFinder class raises an event to notify those interested (mostly the HidCreator class) that a device has been discovered. The HidCreator class then raises an event containing the newly created HID device. This seems like the correct method, however, confirmation either way would be appreciated.

Below is a dumbed down example of the code in question.

public class HidFinder
{
    public event EventHandler<HidFoundArgs> HidFoundHandler;

    private void DeviceAdded(object sender, EventArrivedEventArgs e)
    {
        OnHidFoundHandler(new HidFoundArgs());
    }

    protected virtual void OnHidFoundHandler(HidFoundArgs e)
    {
        EventHandler<HidFoundArgs> handler = this.HidFoundHandler;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

public class HidCreator
{
    private readonly HidFinder hidFinder;

    public event EventHandler<IHidDevice> HidDeviceCreatedHandler;

    public HidCreator(HidFinder hidFinder)
    {
        this.hidFinder = hidFinder;
        this.hidFinder.HidFoundHandler += HidFinderOnHidFoundHandler;
    }

    private void HidFinderOnHidFoundHandler(object sender, HidFoundArgs hidFoundArgs)
    {
        // Create a new HID
        var newHidDevice = Factory.CreateMethod();
        OnHidDeviceCreatedHandler(newHidDevice);
    }

    protected virtual void OnHidDeviceCreatedHandler(IHidDevice e)
    {
        EventHandler<IHidDevice> handler = this.HidDeviceCreatedHandler;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

Solution

  • It generally looks as good design, but I would make two changes:

    1. Factory seems like some global object, it would be better to use Dependency Injection, for better unit testing for example.
    2. Change Factory.CreateMethod to use parameters, as we don't know what exact implementation of IHidDevice will be created and if we won't need some additional info from HidFoundArgs

    Code after changes:

    public class HidCreator
    {
        private readonly HidFinder hidFinder;
        private readonly IHidDeviceFactory factory;
    
        public event EventHandler<IHidDevice> HidDeviceCreatedHandler;
    
        public HidCreator(IHidDeviceFactory factory, HidFinder hidFinder)
        {
            this.factory = factory;
            this.hidFinder = hidFinder;
            this.hidFinder.HidFoundHandler += HidFinderOnHidFoundHandler;
        }
    
        private void HidFinderOnHidFoundHandler(object sender, HidFoundArgs hidFoundArgs)
        {
            // Create a new HID
            var newHidDevice = factory.Create(HidFoundArgs.ToCreationParameters(hidFoundArgs));
            OnHidDeviceCreatedHandler(newHidDevice);
        }
    
        protected virtual void OnHidDeviceCreatedHandler(IHidDevice e)
        {
            EventHandler<IHidDevice> handler = this.HidDeviceCreatedHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
    
    public interface IHidDeviceFactory
    {
        IHidDevice Create(HidCreationParameters parameters);
        ...
    }
    
    public class HidCreationParameters
    {
       ...
    }
    
    public class HidFoundArgs
    {
        public static HidCreationParameters ToCreationParameters(HidFoundArgs args)
        {
            ...
        }
    }