6

I have a confusion regarding Factory Pattern there are basically two ways You can implement that.

Approach 1:

public interface IProductFactory
{
    IProduct GetProductA();
    IProduct GetProductB();
    IProduct GetProductC();
}

public class ProductFactory : IProductFactory
{
    public IProduct GetProductA()
    {
        //some implementation goes here
    }
    public IProduct GetProductB()
    {
        //some implementation goes here
    }
    public IProduct GetProductC()
    {
        //some implementation goes here
    }
}

Approach 2:

public enum ProductType
{
    ProductA = 1,
    ProductB = 2,
    ProductC = 3
}

public interface IProductFactory
{
    IProduct GetProduct(ProductType productType);
}

public class ProductFactory : IProductFactory
{
    public IProduct GetProduct(ProductType productType)
    {
        switch (productType)
        {
            case ProductType.ProductA:
                //return IProduct with specific implementation
                break;
            case ProductType.ProductB:
                //return IProduct with specific implementation
                break;
            case ProductType.ProductC:
                //return IProduct with specific implementation
                break;
            default:
            //return null
        }
    }
}

Pros of both approaches

Approach 1:

  1. benefit of compile time checks that the implementation class will be forced to provide the corresponding methods.

Approach 2:

  1. Implementation will have a benefit of shorter no. of lines of code.
  2. Interface does not become fragile, it won't change as the new products keep on adding.

Cons of both approaches

Approach 1:

  1. Lines of code becomes large.
  2. As more number of Products are implemented, the interface changes and hence it is hard to follow Liskov's Substitution Principle.

Approach 2:

  1. Since it is hiding internal details of GetProduct, it is hard to tell what the Factory will return when a specific type of enum is passed.
  2. You might get into run time exceptions

I am still struggling to decide on which approach to use?


Note: I am only aware of these two approaches, there might be different approaches also.

2
  • 1
    Why do you need an interface for the product - IProduct? Will products have different behaviour? This is a candidate for the abstract base class.
    – CodeART
    Aug 28, 2013 at 8:08
  • @CodeWorks Products will be having different implementations/ behaviours as You can say it. Yes in reality it is an abstract class but for sake of simplicity I have shown it as an Interface here.
    – Devesh
    Aug 28, 2013 at 8:35

2 Answers 2

4

Both approaches break Liskov Substitution Principle. Correct implementation will look smth. like:

public interface IProductFactory
{
    IProduct GetProduct();
}

public class Product1Factory : IProductFactory
{
    public IProduct GetProduct()
    {
        return new Product1(); //configure instance here
    }
}

public class Product2Factory : IProductFactory
{
    public IProduct GetProduct()
    {
        return new Product2(); //configure instance here
    }
}

public class Product3Factory : IProductFactory
{
    public IProduct GetProduct() //configure instance here
    {
        return new Product3();
    }
}
5
  • I have never seen Factory Implementation like that. If I do it like that what is the point of even creating a factory? Please explain.
    – Devesh
    Aug 28, 2013 at 8:41
  • Apologies if that sounded rude :)
    – Devesh
    Aug 28, 2013 at 8:49
  • Here probably you will need another factory to create those factories. Indeed I also do not see the use here...
    – oalan
    Aug 28, 2013 at 10:15
  • 1
    @shankbond If you look at Abstract Factory class diagram, it is exactly what I wrote here. E.g. ADO.NET implements this pattern with its DbProviderFactory
    – almaz
    Aug 28, 2013 at 14:19
  • 3
    @oalan You don't need factories to create another factories:). There will be a place in the code where you know which factory you want to use, be it in code or a connection string in configuration file. I didn't say that this pattern should be used frequently. It's quite heavyweight for what devs usually need. In most real-world cases IoC framework is the factory that does all the magic.
    – almaz
    Aug 28, 2013 at 14:30
2

Approach 2 is the classical Factory Pattern. This pattern is nothing to do with LSP. To ensure LSP is not violated in the client programs, you need to carefully design IProduct interface in such a way that the client program that is operating on IProduct would continue to operate without any modification irrespective of the concrete product that actually implements IProduct. If, you observe you are violating LSP redesign the interfaces.

For example it may be better to create one interface for a category of products if these categories differ in the way client communicates with them.

public interface IPerfume
{
    //Methods specific perfume products
}

public interface IAutomobile
{
    //Methods specific to automobiles
}

Then, you define one factory for each category of products. PerfumeFactory to create perfume products and AutomobileFactory to create automobiles.

The example may not sound fancy but that is all I can think of now.

1
  • 1
    +1. this is closest to the right answer of the 3 so far. The points about IProduct are right on. In addition, Approach 1 is basically trying to be the Abstract Factory Pattern without being an abstract factory. Both approaches suffer from interface-itis, IMHO. They are simply not necessary here.
    – radarbob
    Sep 12, 2013 at 0:52

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.