Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract Factory Pattern - Point of Concrete Factories

Here is the way I typically see the Abstract Factory Pattern shown:

public abstract class Factory 
{ 
    public abstract Product GetProduct(); 
}

public class ConcreteFactory1 : Factory 
{ 
    public override Product GetProduct() {  return new Product1();  } 
}

class ConcreteFactory2 : Factory 
{
    public override Product GetProduct() { return new Product2(); } 
}

interface Product 
{ 
    void SomeMethod(); 
}

class Product1 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("1"); } 
} 

class Product2 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("2"); } 
}

class Program
{
    static void Main(string[] args)
    {
        Factory f = null;
        Product p = null;
        switch (args[0])
        {
            case "1":
                f = new ConcreteFactory1();
                p = f.GetProduct();
                break;
            case "2":
                f = new ConcreteFactory2();
                p = f.GetProduct();
                break;
        }
        p.SomeMethod();
    }
}

I typically write it like this, which is not the true pattern:

interface Product 
{ 
    void SomeMethod(); 
}
class Product1 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("1"); } 
} 
class Product2 : Product 
{ 
    public void SomeMethod() { Console.WriteLine("2"); } 
}
public static class Factory 
{ 
    public static Product GetProduct(prodType) 
    {
        Product p = null;
        switch (prodType)
        {
            case "1":
                p = new Product1();
                break;
            case "2":
                p = new Product2();
                break;
        }
        return p;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Product p = Factory.GetProduct(args[0]);
        p.SomeMethod();
    }
}

My question is - what is the advantage of the concrete factories? I have never understood the point - it just seems to add another unnecessary layer. The second example seems much more concise and straightforward.

like image 224
user210757 Avatar asked Jun 21 '12 21:06

user210757


1 Answers

Since Odrade agrees with me (guess I'm not completely off my rocker) I'll post this as an answer:

I think, and correct me if I'm mistaken, is that normally your base level code has no concept of the concrete factory used. Nor does it care to specify the (in your case) product type via prodType. Instead, the concrete factory implementation is fed via some form of dependency injection to your abstract factory, and your code goes on its merry way without having any concept of what factory is being used, or the concrete types needed. Especially if those concrete factory implementations are provided by 3rd party consumers of your API.

The Wikipedia article on it provides a decent example regarding operating system GUI construction: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

Essentially, your code, in your library can function just fine without knowing any implementation details or dependencies on the operating system used. When you (or a consumer of your API) then go to migrate to Linux (in this Wikipedia example), you simply implement a LinuxFactory and LinuxButton and feed it into your API. If instead, like in your typical example, you control it via an input, say an enumeration, then your factory needs to know about Linux:

public static class Factory 
{ 
    public static Button GetButton(operatingSystem) 
    {
        switch (operatingSystem)
        {
            case "windows":
                return new WindowsButton();
            case "macintosh":
                return new MacButton();
        }
    }
}

How does Linux get factored in now? Well it can't unless you add the support. Plus now all consumers of your API are indirectly dependent on all operating system implementations.

EDIT: Note that Factory Pattern and Abstract Factory Pattern are two completely different concepts. Regarding your concerns with why you asked the question in the first place, abstract factory patterns are not always necessary. If you don't need one, then don't add the complexity of one. If you just need a simple factory (which your second example is a variation of) then use it. Right tool for the right job and all that.

like image 198
Chris Sinclair Avatar answered Sep 28 '22 08:09

Chris Sinclair