Skip to content
loading...

re: How to avoid the Factory pattern in C# VIEW POST

FULL DISCUSSION
 

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;
       }
    }
}

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();
  }
}
 

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.

 

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.

 

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.

 

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.

 

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.

code of conduct - report abuse