Abstract Factory Pattern - Point of Concrete Factories
Asked Answered
H

4

6

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.

Hundred answered 21/6, 2012 at 21:58 Comment(3)
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.Consistory
If you have lots of products, your single factory will get very, very big. If you ever decide to change a factory a product is made at, all your clients will have to change as the factory is not abstracted away from them. They have a direct reference to your single factory.Watersick
Or maybe if you want to do a Factory of Factories manouvre, and there's some common code to make you prefer it over "IFactory" interface.Obeah
C
8

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.

Consistory answered 21/6, 2012 at 22:16 Comment(2)
+1; good answer. I'd like to emphasize the point made about whether or not a pattern is needed. I think a common mistake is thinking that because one pattern is more evolved than another, it is somehow "better". It's not - it's just more adapted to a particular scenario which requires more complexity. If you don't have the complex demands which the pattern satisfies, use a simpler approach. Patterns are just guides to solutions which work at different levels of software, each has benefits and liabilities. Your specific needs will mediate the payoff each gives.Ciri
I am with you. And it seems my first example is an abstract factory, and they way i prefer to do things example is the Factory pattern. It seems I am usually more in need of a Factory.Hundred
H
2

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

Hardi answered 21/6, 2012 at 22:17 Comment(0)
S
1

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.

Sliding answered 22/6, 2012 at 4:16 Comment(0)
S
1

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.

Slight answered 22/6, 2012 at 4:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.