I've been seeing a lot of code recently that looks like this:

public interface IFoo { int Bar(); }

public static class Foo 
    public static IFoo Create() { return new FooImpl(); }
    private class FooImpl : IFoo
        public int Bar () { ... }

Basically, there is a contract defined by an interface, the the main business object class is a static class that provides factory methods, and there is an embedded class that provides the actual implementation.

There are some advantages to this pattern especially, the clean separation between the contract and the implementation. Still, it seems a little ugly to me: especially the naming of a static factory class with a business object name rubs me the wrong way.

My questions are...

  1. Is this an established pattern or style of development?
  2. Are there any other advantages besides a rigorous hiding of implementation?
  3. Is there a better way to achieve the same goals?

It looks like a crippled cross between Abstract Factory and Factory Method. It includes a full class, not just a method, but that class is a static utility class, not abstract, thus you have no way of switching to a different Foo implementation.

Hiding the implementation of Foo is fine, however this design is not unit testable. Clients most likely call Foo.Create directly, thus unit tests have a hard time replacing / mocking out FooImpl to any different implementation of IFoo.

I agree with you in that the naming is bad too. The factory should not be mixed with the product it creates.

An alternative could of course be a full Abstract Factory implementation, but this may be overkill for a single product. Very often this can be replaced by Dependency Injection, which is simpler and easy to unit test.

  • Yep, you're right. This is not unit testable. – afeygin Sep 27 '11 at 15:02

I would regard the approach as being in many circumstances the best possible in a framework which does not allow interfaces to include public static helper methods. I would consider IFoo.Create() preferable to Foo.Create() if such a thing were allowed, but unfortunately (at least in .NET languages) it isn't.

Despite the unfortunate naming of the factory method, I think such an approach is optimal in cases where:

  1. There exists a single class which will be a reasonably good fit for the needs of code which won't need to use any features beyond those implemented by the interface.
  2. Some clients may need things which can be used as implementations of the interface but which support other abilities as well, and the optimal internal design of an implementation which supports the added features may be totally different from the optimal design for an implementation which doesn't.
  3. Methods which can be used with basic implementations of the interface should also be usable with the fancier implementations.

If a method takes a parameter of the "ordinary implementation class" type, such a method will not be useful with any of the fancier implementations. Thus, unless there is some reason to have a method reject the fancier implementations, methods should generally use the interface type. If a variable will never be passed to any methods except as an interface type, then the variable itself should probably be declared as that same interface type.

Although in situations involving a parameterless constructor/factory there may not be much advantage to using IWidget foo = Widget.Create() over IWidget foo = new Widget(), a factory method which accepts parameters can vary the type of the created object based upon the parameter values it is given. This can be especially useful in cases involving immutable types. For example, a method ImmutableSequence<T>.Create(IEnumerable<T> source); could copy source to an array and encapsulate that in an immutable wrapper in cases where no obviously-better alternative behavior suggests itself, but in cases where it recognizes the source type it might be able to do something better. For example, if source instance implements an AsImmutableSnapshot() method, the Create method could chain to that and avoid having to create an extra layer of nesting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.