views:

1003

answers:

6

I am struggling to understand what my factory class should do in my DDD project. Yes a factory should be used for creating objects, but what exactly should it be doing. Consider the following Factory Class:

    public class ProductFactory
    {
        private static IProductRepository _repository;

        public static Product CreateProduct()
        {
            return new Product();
        }

        public static Product CreateProduct()
        {
            //What else would go here?
        }

        public static Product GetProductById(int productId)
        {
            //Should i be making a direct call to the respoitory from here? 
            Greener.Domain.Product.Product p = _repository.GetProductById(productId);
            return p;
        }
    }

Should i be making a direct call to the repository from within the factory?

How should i manage object creation when retriving data from a database?

What do i need to make this class complete, what other methods should i have?

Should i be using this class to create the Product object from the domain and repository from right?

Please help!

A: 

In the example given above, I'm a little unclear on the distinction between your factory and the repository. I wonder if you shouldn't simply add CreateProduct as a method to the repository, and using DI to push the repository into code that needs it? If the factory isn't doing anything, etc...

Or if you just want it to act as a globally registered repository, perhaps something like:

public static IFooRepository Default {get;private set;}
public static void SetRepository(IFooRepository repository) {
    Default = repository;
}

(in my mind it seems clearer to separate the "set" in this case, but you don't have to agree)

and have the callers use var product = YourFactory.Default.CreateProduct(); etc

Marc Gravell
A: 

I personally would use the factory in couple of circumstances:

1) Something elsewhere governs what type of objects this factory returns (ie. it can return objects depending on circumstances. For example return a stub object when I am testing, return an actual implementation when I am not (this is obviously more of Inversion of Control / Dependency Injection issue - but if you do not want to add containers to your project just yet)).

2) I have quite complex objects that have containers, dependencies, other relation etc. and they need to be built carefully to avoid creating null or meaningless references. For example if I have a Schedule object I may need some start, end date fields set - if the logic for retrieving, figuring out these date is complex enough I may not want the calling class to know about it and just call the default factory method that created the schedule object.

Hope this helps.

Tomas Pajonk
+2  A: 

What should go in your factory's Create method is whatever is necessary to put a brand spanking new object into a VALID state.

Now, for some objects that means you won't do anything except this:

public Product Create()
{
   return new Product();
}

However, you may have business rules, default settings, or other requirements that you want to enforce when an object is created. In that case, you would put that logic in that method.

And that's part of the benefit of the Factory. You now have one and only one place where that special logic resides, and only one place where a new object gets created.

Chris Holmes
+3  A: 

Should i be making a direct call to the repository from within the factory?

No, don't use a factory when your retrieving stuff, use a factory only when you are creating it for the first time.

How should i manage object creation when retriving data from a database?

Pass that data into the factory, if it is required for the object's initial creation.

What do i need to make this class complete, what other methods should i have?

Many factories are not even individual classes, they are just methods that provide object creation. You could fold the factory method into another class, if you felt like it was just going to call a parameterless constructor.

Should i be using this class to create the Product object from the domain and repository from right?

The repository is for getting (in a sense creating) existing objects, the factory is for the first time you create an object.

Initially many factories won't do much except call a constructor. But once you start refactoring and/or creating larger object hierarchies, factories become more relevant.

Explanation and Example:

For instance, in the project I'm working on I have an excel processor base class and many subclasses implementing that base class. I use the factory to get the proper one, and then call methods on it, ignorant of which subclass was returned.(Note: I changed some variable names and gutted/altered a lot of code)

Processor base class:

public abstract class ExcelProcessor
{
      public abstract Result Process(string ExcelFile);
}

One of the Processor subclasses:

public class CompanyAExcelProcessor : ExcelProcessor
{
     public override Result Process(string ExcelFile)
     {
      //cool stuff
     }
}

Factory:

 public static ExcelProcessor CreateExcelProcessor(int CompanyId, int CurrentUserId)
 {
      CompanyEnum company = GetCompanyEnum(CompanyId);
      switch (company)
      {
           case CompanyEnum.CompanyA:
                return new CompanyAExcelProcessor();
           case CompanyEnum.CompanyB:
                return new CompanyBExcelProcessor();
           case CompanyEnum.CompanyC:
                return new CompanyCExcelProcessor(CurrentUserId);
           //etc...
      }
 }

Usage:

ExcelProcessor processor = CreateExcelProcessor(12, 34);
processor.Process();
Mark Rogers
+3  A: 

Be carefull, there are two reasons to instantiate a new object : Creating it and rehydrating it from the database.

The first case is handled by the factory. You can provide several methods to create an object on the factory. Factory methods should return valid objects, so you can pass parameters to these methods to provides required information.

The factory method can also chose the actual type to instantiate based on parameters.

You should not mix this with rehydrating from the database. This kind of instantiation should take values from the datarow and instantiate the object with it. I usualy call this a data builder instead of a factory.

The main difference is that the factory will instantiate an object with a new identity while the databuilder will instantiate an object with an already existing identity.

Think Before Coding
I don't think it's common to make the data builder / factory distinction you discribe here. Create and rehydrating are both classic factory duties.
Mark Rogers
The factory is usualy in the domain while the data builder is in the persistance infrastructure.
Think Before Coding
A: 

@ThinkBeforeCoding - in @m4bwav's example, the factory is getting a valid ID from a helper method, but it's not creating a new record in a persistence layer anywhere. If, however, I'm using a database auto-generated identity column as my identities, it seems like a factory would have to call into the repository to do the initial object creation. Can you comment on which method is "correct"?