user210757
user210757

Reputation: 7376

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.

Upvotes: 6

Views: 2075

Answers (4)

tallseth
tallseth

Reputation: 3675

The "Abstract Factory" is really a bad name for this pattern. A much better name is the "Kit" pattern, which the GoF also used. I agree, in the example you gave, it is over-design. it makes a lot more sense when your factories have the responsibility of creating many objects that work together. Then, different groups of them (kits, if you will) get created by different factories, under a given set of runtime or design time conditions.

This is a really good article about it. There non-software analogy of metric vs english socket sets is perfect.

Upvotes: 1

ktutnik
ktutnik

Reputation: 7262

what is the advantage of the concrete factories? I have never understood the point - it just seems to add another unnecessary layer

factory (in general - Factory Method, Abstract Factory etc) used to resolve a complex-creating type of object, if your Product1 and Product2 require different type of initialization then it wont be a good idea to hardcode it on your concrete factory.

Upvotes: 1

Chris Sinclair
Chris Sinclair

Reputation: 23198

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.

Upvotes: 8

Les
Les

Reputation: 10605

I would call your approach a Factory pattern, which is different from an abstract Factory.

Upvotes: 2

Related Questions