Home > dotnet 4, SOLID > Interface & TDD Part -2: The Factory pattern

Interface & TDD Part -2: The Factory pattern

If you guys remember back in June I did a post on interface and TDD. A very simple example in which we applied SOLID principle and separation of concern to re factor our code. I think it is more like re-factoring in our thinking, when we talk about agile we have to think like one.

If you haven’t read it yet please read it here and give me your feedback. I like the comments and came across this comment by Mr. Monk…

Monk :

So in this way how would you prevent that the fake classes get compiled for a release version?

Comment

I quickly replied to the good fella but realize will it make sense, is this really going to make things clear to him . It’s not making sense to me so how would it make sense to him. So I thought I better post it, as the crux of this matter is not in the code but in the thought process i.e. agile thinking. So lets tackle this and see what’s the problem is …

As you can see in the fake test and in the real test we are newing up the object and although it solves our purpose but it is not a good design.

  1. We have hard code the class and we have tight coupling.
  2. We are sort of breaking the single responsible principle as the invoking code (consuming code) is creating the object and using it too.

So lets see how can we can decouple the dependency and create a class which does the job of creating the right object so that we can make sure that all the test when run will invoked the fake drive method and when we run this in production then the real drive code gets executed.

And the answers to this is …(drum roll) …Factory Pattern. I know it’s a very old pattern we all have knows but never really seen in practice or makes sense…aha so we have heard that’s 50% job done as Factory means creating something and we have a problem here of creating something ;-). Lets start with a simple abstract class and we will call it BaseDriveFactory

public abstract class BaseDriveFactory
{
    public abstract IDrive CreateDrive();
}

As you can see we are creating an abstract class which creates an object of type IDrive ( Deep slow breath we are moving into the zone )…

 

Then we create 2 Factory classes for Fake and Real Drive Object …

public class FakeDriveFactory : BaseDriveFactory
{
    public override IDrive CreateDrive()
    {
        return new FakeDrive();
    }
}

and

public class RealDriveFactory : BaseDriveFactory
{
    public override IDrive CreateDrive()
    {
        return new RealDrive();
    }
}

Now you might be thinking hmm..may be I can write an if else logic to decide which object to call and depending on some flag, int or enum I will do the switch and return the right object. Well in theory it is alright but we haven’t thought agile enough and some single responsibility principles so we do some more thinking .

Now the factory are in place and we are ready to go and do the magic ..hmm may be we need a generator class which will do the creation ..good point lets do it ..

public class DriveFactoryGenerator
{
    private readonly IDrive fakeDrive;
    private readonly IDrive realDrive;

    public DriveFactoryGenerator(BaseDriveFactory factory)
    {
        fakeDrive = factory.CreateDrive();
        realDrive = factory.CreateDrive();
    }

    public void Drive(IDriveFactorySettings settings)
    {
        if (settings.ObjectFactory == "default")
        {
            realDrive.Drive();
        }
        else
        {
            fakeDrive.Drive();
        }
    }
}

Sounds interesting and looks good we have done re-factoring quite well and separation of concerns is also well implemented. If you notice I have also introduce and interface called IDriveFactorySettings. Now you must be saying what the heck why we need it, well agile thinking means anticipation and I will do a post very soon on that too but for the time being lets see what it looks like

 

public interface IDriveFactorySettings
{
    string ObjectFactory {get;set;}
}

As you can see with that interface I am just creating a contract(interface) and saying that any class which wants to manage this has to implement the interface and we are in business. I am not hardcoding it to say that it has to be from a config file or xml or registry. This is the beauty of separation of concerns and interface design is that we don’t care about the implementation.

So in order to override the behaviour all I have to do is change the IDriveFactorySettings and we get what we want. As far as the problem Mr. Monk has had all I have to do is implement a BaseTest class which all my UnitTest will inherit and have the objectfactory as anything other than “default”

So i would do something like this

public class FakeDriveFactorySettings : IDriveFactorySettings
{
    public string ObjectFactory
    {
        get { return "Fake"; }
        set { ObjectFactory = value; }
    }
}

 

and the base test class will look like

 

public class BaseTest
{
    private readonly IDriveFactorySettings _settings;
    private readonly DriveFactoryGenerator factoryGenerator;
    private readonly BaseDriveFactory factory;
    public BaseTest()
    {
        _settings = new FakeDriveFactorySettings();
        factory = new FakeDriveFactory();
        factoryGenerator = new DriveFactoryGenerator(factory);
    }

    public virtual void TestDrive()
    {
        factoryGenerator.Drive(_settings);
    }
}

and the test would look like

[TestClass]
public class DriveTest : BaseTest
{
    public override void TestDrive()
    {
        base.TestDrive(); // calling the fake one
                          //as it already set for
                          //the entire test
                         
    }
}

The final class diagram..
Class Diagram

that’s it from me and guys keep your comments coming.I would like to know your perspective into the whole SOLID way of thinking and as well interesting problems you guys face in your daily coding 🙂

Advertisements
  1. November 19, 2010 at 12:31 am

    Hi Prashantbhai,

    I was wondering why not to use some sort of mocking framework instead of Faking a class. As a side comment, there are strickt requirement if you want to mock a class and a while back, I wanted to mock WebResponse (http/https/ftp) and I discovered WebRequest was a good example of Factory Pattern, after reflecting the assembly, learned few new things about it too.

    Interesting fact is how Microsoft comes up with which pattern to use when and it perfectly fits the scenario (Something I have to learn soon….)

    It would be good if you can in future (in design pattern articles) write something about usage scenario at the start of your article.

    Carry on the good work,

    Nimesh

    • November 21, 2010 at 11:17 pm

      Hi Nimesh,
      Thanks for your comment and I agree with your point, infact in my previous post “The art of mocking part-2” I did touched about the point about Fake Vs Mock objects and it’s more upto the individual. My general thumb rule is if an object is hard to instanciate or take a lot of resources and pluming I would go for Mock but for business classes or dto’s a fake would be good enough ( no solid logic for that but just a preference). Also it depends on projects sometimes you have to cut corners because of time constraints and Project Manager/Testers breathing down your neck ;-).

      In future I will try my best to mention the usage scenarios at the begining of my article.

      Cheers

      Prashant Brall

      • November 24, 2010 at 6:04 am

        Thanks, I do agree with the cut corners approach at times 🙂 Looking forward for more posts. I love reading your posts.

  2. November 29, 2010 at 12:42 pm

    Good day I was fortunate to discover your Topics in digg
    your subject is exceptional
    I learn a lot in your Topics really thanks very much
    btw the theme of you blog is really outstanding
    where can find it

  1. December 1, 2010 at 6:05 am

Leave a Reply

Fill in your details below or click an icon to log in:

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: