Replacing simple factories with Func<TResult> delegate

I’ve recently noticed the emergence of a recurring pattern in my code. Each project has the same class in it, and this duplication has really been bothering me. The solution to this repetition just hit me this morning while I was reading Jon Skeet’s “C# In Depth.”

First, let me illustrate the pattern I was using and why it’s a problem.

I’ve been refactoring 1-tiered legacy code into something testable. This has involved creating a data layer class, typically called DataProvider which implements an IDataProvider interface so that I can easily mock out the data access.  Now, because any kind of data access is extremely likely to have unmanaged resources, IDataProvider extends IDisposable.

    public interface IDataProvider : IDisposable
    {
        string GetFoo(int id);
        // imagine more members
    }

    public class DataProvider : IDataProvider
    {

        private readonly DatabaseContext _context;

        public DataProvider(string connectionString)
        {
            _context = new DatabaseContext(connectionString);
        }

        public string GetFoo(int id)
        {
            return _context.Foos.Where(x => x.Id == id);
        }

        // imagine more members

        public void Dispose()
        {
            if (_context != null)
            {
                _context.Dispose();
            }
        }
    }

This is good, but in order to take advantage of IDisposable in my Controller or Presenter, I need to create a concrete instance of the class each time I go to access the persistence layer.

    public class Presenter
    {
        private readonly IView _view; 

        public Presenter(IView view)
        {
            _view = view;
        }

        private SetDefaultFoo()
        {
            using (var provider = new DataProvider("some connection"))
            {
                _view.Foo = provider.GetFoo(1);
            }
        }
    }

Which means I still can’t put the presentation/business logic under test without hitting the database. To get around this, I created a very simple factory whose sole purpose is to return a new instance of DataProvider.

    public interface IDataProviderFactory
    {
        IDataProvider CreateProvider(string connectionString);
    }

    public class DataProviderFactory : IDataProviderFactory
    {
        public IDataProvider CreateProvider(string connectionString)
        {
            return new DataProvider(connectionString);
        }
    }

This also implements an interface for easy mocking.

        [TestMethod]
        public void SomeTest()
        {
            var provider = new Mock<IDataProvider>();
            var factory = new Mock<IDataProviderFactory>();
            factory.Setup(f => f.Create()).Returns(provider.Object);

            var view = new Mock<IView>();

            //some more set up

            var presenter = new Presenter(view.Object, factory.Object);

            //some assertions
        }

Where our Presenter now looks like this.

    public class Presenter
    {
        private readonly IView _view;
        private readonly IDataProviderFactory _factory;

        public Presenter(IView view, IDataProviderFactory factory)
        {
            _view = view;
            _factory = factory;
        }

        private SetDefaultFoo()
        {
            using (var provider = _factory.CreateProvider("someconnection"))
            {
                _view.Foo = provider.GetFoo(1);
            }
        }
    }

So, now I’ve cleanly separated the data layer implementation from the presentation logic, just like I’ve done before for other purposes. However, each project has a unique IDataProvider, so the factory class can’t be referenced from a common library. I’ve found myself copy/pasting the factory class into each project, which is the worst kind of sin.

So, how do we fix this?

Well, we could use an IoC container, or pass a type argument into the factory. Those are viable solutions, but I don’t want the overhead of an IoC framework right now and I’m also not quite yet in a position to share code across these projects. So, I need a factory (for now). This can be solved relatively easily though by using a Func<TResult> instead of a handwritten factory, because Func<TResult> basically is a factory.

    public class Presenter
    {
        private readonly IView _view;
        private readonly Func<IDataProvider> GetDataProvider;

        public Presenter(IView view, Func<IDataProvider> providerFactoryFunc)
        {
            _view = view;
            GetDataProvider = providerFactoryFunc;
        }

        private SetDefaultFoo()
        {
            using (var provider = GetDataProvider())
            {
                _view.Foo = provider.GetFoo(1);
            }
        }
    }

Which gets called like so.

    class Test
    {
        [TestMethod]
        public void SomeTest()
        {
            var provider = new Mock<IDataProvider>();
            var factory = () => provider.Object;

            var view = new Mock<IView>();

            //some more set up

            var presenter = new Presenter(view.Object, factory);

            //some assertions
        }
    }

Completely removing any need for a special factory class at all.

Hopefully this shows that there’s more than one way to skin a cat and that delegates are an extremely powerful technique when used properly. Often, half the battle is remembering that it’s one of the tools in your box. If you’ve never used the Func type before, DotNetPearls has some really useful examples.

Advertisements

, , , , , , ,

  1. Leave a comment

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: