DEV Community

Brian Berns
Brian Berns

Posted on

How to avoid the Factory pattern in C#

Domain model classes

Object-orientation is great when classes represent actual domain model objects. For example, if we're modeling animal sounds, Dog and Cat classes make good sense:

interface IAnimal
{
    string Speak();
}

class Dog : IAnimal
{
    public string Speak() => "Woof";
}

class Cat : IAnimal
{
    public string Speak() => "Meow";
}
Enter fullscreen mode Exit fullscreen mode

Factory pattern

Now, let's say we need to write a function that creates an arbitrary animal and asks it to speak. Unfortunately, there's no way to add a constructor to the IAnimal interface. One way to work around this limitation is the Factory design pattern, which creates a separate "factory" class for each of our domain model classes:

interface IAnimalFactory
{
    IAnimal CreateAnimal();
}

class DogFactory : IAnimalFactory
{
    public IAnimal CreateAnimal() => new Dog();
}

class CatFactory : IAnimalFactory
{
    public IAnimal CreateAnimal() => new Cat();
}

Enter fullscreen mode Exit fullscreen mode

With the new IAnimalFactory interface, we can create dogs and cats and make them speak:

class Program
{
    static void Main(string[] args)
    {
        Run(1, new DogFactory());
        Run(2, new CatFactory());
    }

    static void Run(int n, IAnimalFactory factory)
    {
        var animal = factory.CreateAnimal();
        Console.WriteLine($"Animal #{n} says '{animal.Speak()}'");
    }
}

// output:
// Animal #1 says 'Woof'
// Animal #2 says 'Meow'

Enter fullscreen mode Exit fullscreen mode

This works fine, but it adds a considerable amount of new code and conceptual overhead, because every domain model class now requires a separate factory class as well. The extra level of indirection can quickly become confusing. Is there a better way?

Factory functions

Functional programming lets us get rid of factory classes altogether. Instead of passing an IAnimalFactory to Run, we can instead pass a "factory function" of type Func<IAnimal>. This takes over the role played by the factory object in the previous implementation:

static void Run(int n, Func<IAnimal> createAnimal)
{
    var animal = createAnimal();
    Console.WriteLine($"Animal #{n} says '{animal.Speak()}'");
}
Enter fullscreen mode Exit fullscreen mode

We can use lambdas to create our factory functions with little ceremony:

static void Main(string[] args)
{
    Run(1, () => new Dog());
    Run(2, () => new Cat());
}

Enter fullscreen mode Exit fullscreen mode

The output is exactly the same. By using functions as first-class objects, we've eliminated an entire category of classes and significantly simplified our code base! If you find yourself tempted to create a factory object in the future, consider using a factory function instead.

Top comments (19)

Collapse
 
thatblairguy profile image
That Blair Guy • Edited

As presented, I can sort of see an advantage to the factory method technique from the standpoint of not knowing at compile time what concrete types will be available at runtime. (E.g. If the factory method is in a different assembly from the one containing the concrete types.)

My strongest argument against it though is that the factory method is tied to whatever class declares it. A class should only have one purpose, and if that purpose is to create objects matching a particular base class/interface, it should be a factory.

I don't generally do a separate factory for each class. Instead, it's one per Interface (or abstract class, or whatever the common base may be). That would look something like this:

static class AnimalFactory
{
    public static Create(AnimalType type)
    {
       IAnimal animal;
       switch(type)
       {
          case AnimalType.Dog:
              animal = new Dog();
              break;
          case AnimalType.Cat:
              animal = new Cat();
              break;
          case AnimalType.Bird:
              animal = new Bird();
              break;
       }
    }
}
Enter fullscreen mode Exit fullscreen mode

This is a common pattern. But, as alluded to above, the drawback to this particular style is that you have to know all the concrete classes in advance.

A compromise then would be a factory class with a constructor which takes a name/value pair consisiting of an enum (e.g. AnimalType) and the matching creation function. The factory class then would have a Create method which takes an AnimalType value as a parameter, looks up the matching creation method, and calls it. There could very likely be an argument on the factory's Create to pass a data structure containing type-specific attributes such as weight, color, beak-size, number of feet, and so forth.

Very rough version for illustration, almost certainly non-compiling:

enum AnimalType
{
  Dog = 1,
  Cat = 2,
  Horse = 3
}

delegate IAnimal AnimalCreationDelegate();

class AnimalDescriptor
{
  public AnimalType Type;

  // This ends up being a delegate
  public AnimalCreationDelegate Creator()
}

class AnimalFactory
{
  IEnumerable<AnimalDescriptor> creatorList;

  public AnimalFactory(IEnumerable<AnimalDescriptor> creators)
  {
    this.creatorList = creators;
  }  

  public IAnimal Create(AnimalType type)
  {
    AnimalCreationDelegate creator = creatorList.Find(type);
    return creator();
  }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shimmer profile image
Brian Berns

Thank you for the detailed response. Examples are definitely helpful! :)

I think what you’ve done is fine since it’s basically a functional approach that avoids the explosion of traditional factory classes. My only suggestion is to use Func<IAnimal> instead of a delegate. The modern syntax is easier to read and work with, IMHO.

Collapse
 
thatblairguy profile image
That Blair Guy • Edited

The delegate is definitely a bit old school, but for purposes of illustration, I felt the explicit signature lent some clarity to what I was trying to communicate. In real-world code, a Func<T> might very well be preferable.

As I commented elsewhere, factories which only wrap a new are good for demonstrating "Here's how a factory works," but don't provide much other value. Having a separate factory for each class, particularly when they're just "wrap the new", is something to avoid; I'm tempted to call it an anti-pattern.

I suspect there's something similar at play here with the description of factory methods. I understand how to write them, you've communicated that pretty darn well. But I'm struggling with the compelling reason why they're preferable to well-designed factory classes.

Collapse
 
smartcodinghub profile image
Oscar

Func are nameless. Making arguably "harder" to understand when you find it in the code. Creating a delegate allows you to name it and make easier to "inject" it using DI. And having a name also expresses what you intend to do with that function.

Collapse
 
thompcd profile image
Corey Thompson

I don't know that this accomplishes the main issue, you still have to know the concrete class in advance. You don't have a concrete class but still have to recompile to add a new type to your enum. I feel that I shouldn't need to add all concrete types to my factory class. By using the author's delegate method, I can define all of my concrete classes where they best fit in my project and just implement a good interface that indicates all of the uses of that class.

The downside of this is definitely traceability though.. Getting a new person on the team to be able to find the source and see what's happening at a glance is a nice perk for sure, which doesn't happen in the more abstract version.

I started doing a lot of JS a year ago.. It seems it's tainted me.

Collapse
 
thatblairguy profile image
That Blair Guy

The enum certainly forces a recompile, but you can use strings instead.

But the Creator methods (whether declared as delegates or Funcs) would encapsulate the knowledge of the concrete classes. All the factory needs to know is that it has a function to call and that function has a specific signature.

Collapse
 
thfsilvab profile image
Thadeu

But, what if I'm building a Beagle and a German Shepherd?

I'd make sense to have two classes that build the same class Dog, but gives me a different ones, based on it's properties.

More code? You're right, but also much more readable.

Collapse
 
shimmer profile image
Brian Berns • Edited

I'm not sure I follow you. Are you saying that we could create Beagle and GermanShepherd as subclasses of Dog? That's true, but I don't see how that would change the situation much.

Can you clarify, or give an example where a factory class makes more sense than a function?

Collapse
 
namhto profile image
Othman Tenich

I don't get why you need this factory anyway. Why not just calling the constructor directly ?

Collapse
 
shimmer profile image
Brian Berns • Edited

Good point. Because this is a toy example, each factory is only used to create a single animal, so they really serve no purpose. Typically, though, a single factory creates multiple objects - for example, in response to a recurring event, or corresponding to rows in a database, etc.

To keep things simple in our case, imagine if Run looked like this instead:

static void Run(IAnimalFactory factory)
{
    for (var n = 1; n <= 10; ++n)
    {
        var animal = factory.CreateAnimal();
        Console.WriteLine($"Animal #{n} says '{animal.Speak()}'");
    }
}

Since we now create 10 instances of each animal class, some sort of factory makes sense, yes?

Collapse
 
thfsilvab profile image
Thadeu

Sometimes, objects become too complex to be handled only by the constructor.

Sometimes you'll also want to apply domain rules in the creation of an object.

Collapse
 
guneyozsan profile image
Guney Ozsan

I feel some anti-pattern issues:

  • It accepts any function that returns IAnimal, not just factories. This can be risky in the long run.
  • It decentralizes factories. This will eventually end up writing plenty of duplicate code, and possible local or private functions that do similar but slightly different initializations, probably when you need more customization.

You can see where it is going.

Collapse
 
shimmer profile image
Brian Berns • Edited

It accepts any function that returns IAnimal, not just factories. This can be risky in the long run.

This is no different from the factory pattern, which accepts any object that implements IAnimalFactory. I don't think there's any risk involved.

This will eventually end up writing plenty of duplicate code

I don't follow you. How does the factory pattern (or my functional version of it) lead to duplicate code? An example might help.

Collapse
 
guneyozsan profile image
Guney Ozsan

Isn't the whole point of factory is to make complex initializations easier? I am not able to see how this can be applicable when factory is not just a wrapper for new. Why would you even use factory (and look for a simplification) when constructor is already more than enough?

Collapse
 
shimmer profile image
Brian Berns

No, the point of the factory pattern is to create an object that implements a particular interface (IAnimal) without knowing the class of the object. You can take a look at an example here.

Collapse
 
guneyozsan profile image
Guney Ozsan

Thank you for pointing this. I'm a Unity developer and in Unity we cannot use constructors at all (it breaks the engine). Plus, interfaces are sometimes anti-pattern (if not most of the time). This sometimes create confusion.

Collapse
 
shimmer profile image
Brian Berns

That’s interesting. Every C# example of a GoF factory design pattern that I’ve seen involves at least one factory class.

Collapse
 
thatblairguy profile image
That Blair Guy

The examples for conveying a concept are rarely effective at showing the power of the concept. (E.g. A factory that simply wraps new MyType();).

And the examples that show how powerful a concept can be (e.g. A factory that demonstrates the provider/strategy pattern) is rarely effective for demonstrating the concept of a factory at its purest level.

My own experience is that simple factories aren't good for much except demonstrating what a factory is. But factories tend to be where the "magic" part of a design pattern is implemented. (Strategy, Decorator, and even Visitor, are all built on Factory.)

Thread Thread
 
shimmer profile image
Brian Berns • Edited

I think we’re in agreement that factories are useful. My only point is that modern C# can accomplish the same thing using functional programming instead of OO classes.

(The GoF book was written before mainstream OO languages supported functional programming.)