What is the difference between Simple Factory, Factory Method, Abstract Factory?

Asked

Viewed 3,182 times

14

What are the main differences between these design patterns? In which situation can one pattern be better than the other?

2 answers

16


All patterns are often abused. They should only be used when it really is a solution to a real problem.

I’ve seen factories being used where I didn’t need them, where the code could build the objects without intermediaries.

Simple Factory

It’s interesting when you don’t really know what kind of object it will be used for. Usually a factory class is created to manage this. In it would have a method that returns the object of the correct type according to some criterion. There are cases that this method can even be static and dispense instantiation something just to consume the factory. It can even do without a class. Of course each case has both advantage and disadvantage.

There are cases where a static method is created in a class, possibly abstract, which is the basis of the classes that will be used to manufacture the object.

A common way is for the selection to be made by a switch, receiving a string or something external. It’s usually a mistake when you get an enumeration. If you know in development time what to go through, then just instate what you need. Of course there are legitimate cases for its use, for example the enumeration has been generated by an external data.

public class PizzaFactory {
    public Pizza CreatePizza(String sabor) {
        if (sabor == "Portuguesa")
            return new Portuguesa();
        if (sabor == "Calabreza")
            return new Calabreza();
        return null;
    }
    ...
}

All flavors derive from Pizza. So where do you need the Pizza I’d call it that:

PizzaFactory fabricaDePizza = new PizzaFactory()
Pizza pizza = fabricaDePizza.createPizza(textBoxPizza);

The text may come from several places, the one I put is obvious but probably inappropriate in actual application.

Some prefer to make the static class, so you don’t need to instantiate anything, just to create what you really want.

Of course this has a maintenance problem. If you create a new flavor you have to stir in the factory class to add it. This is not the end of the world in much of the applications, but it is in some.

The solution is to create a mechanism to record the classes of flavors in the factory class or to reflect on well-standardized cases. The first would be something like this:

class static PizzaFactory {
    private Dictionary<string, Pizza> pizzas = new Dictionary<string, Pizza>();
    public static void registerPizza(String nome, Pizza pizza) => pizzas[nome] = pizza;
    public static Pizza createPizza(String nome) => pizzas[nome].createPizza();
}

Then each flavor class will register and have a way to instantiate. The factory class does not need to know each of the flavors.

class Portuguesa : Pizza {
    ...
    static Pizza() => PizzaFactory.registerPizza("Portuguesa", new Portuguesa());
    public override Pizza createPizza() => new Portuguesa();
    ...
}

Obviously this is not the complete and most robust code possible, but overall this solution is suitable in several cases.

Method Factory

This pattern is used in the case that you need to build instances in a specific way, do something else that the construction would normally do, that is, you don’t need to be aware of how to consume the construction of the object in a specific way. Obviously you can have several different manufacturing lines for the same class, allowing flexibility.

This is done through subclass. Note that each subclass can have its own implementation, it does not matter to the consumer of that pattern which is the object and how it was built, it just wants the result.

Just like the previous pattern It is a way of being able to build new objects without knowing all the existing ones. A maintenance that creates a new type can be consumed without any part of the code other than the new type being written.

Note that the class to be manufactured also does not need to be aware that it will have a factory.

public abstract class PizzaFactory {
    protected abstract Pizza Make();
    public Pizza GetPizza() => this.Make(); //este é o método de fábrica
}

public class PortuguesaFactory : PizzaFactory {
    protected override Pizza Make() {
        Portuguesa pizza = new Portuguesa();
        pizza.GetHam();
        pizza.GetPea();
        pizza.GetOnion();
        pizza.GetEgg();
        return (Pizza)pizza;
    }
}

This way you can call a pizza that already makes picks up the specific ingredients without having to worry about it. In other flavor the ingredients are other, but it is not your problem, the factory of each one knows what to do, just call the GetPizza() that goes for all flavors. Something like this:

PizzaFactory fabrica = new PortuguesaFactory();
Pizza pizza = fabrica.getPizza();

There are a few different versions of what the right way to do it is. It’s common for people to claim that the way they like it is the right way. I honestly don’t know what’s right when there are so many sources. This is one way to implement it that works.

Abstract Factory

It’s essentially a factory. It is used when we have an array of items that relate and need an abstract creation that fits any item. It allows you to create various settings with related items. Thus it is possible to assemble new options independently without one being aware of the other.

In this more complex example we create different flavors and types of pizzas:

public interface IPizzaIngredientFactory {
    public Massa createMassa();
    public Molho createMolho();
    public Queijo createQueijo();
    public Acessorios[] createAcessorios();
    public Carne createCarne();
}

public class PremiumPizzaIngredientFactory : IPizzaIngredientFactory {
    public Massa createMassa() => new MassaFinaCrocante();
    public Molho createMolho() => new MolhoTomateEspecial();
    public Queijo createQueijo() => new QueijoMussarela();

    public Acessorios[] createAcessorios() => new Acessorios { new MiniAzeitona(), new CebolaRoxa() };
    public Carne createCarne() => new CarneRalada();
}

public abstract class Pizza {
    public string Nome;
    protected IMassa Massa;
    protected IMolho Molho;
    protected IAcessorios[] Acessorios;
    protected IQueijo Queijo;
    protected ICarne Carne;
    public abstract void Prepare();
}

public class Calabreza : Pizza {
    IPizzaIngredientFactory ingredientFactory;
    public CheesePizza(IPizzaIngredientFactory ingredientFactory) ingredientFactory = ingredientFactory;
    public override void Prepare() {
        Massa = ingredientFactory.CreateMassa();
        Molho = ingredientFactory.CreateMolho();
        Queijo = ingredientFactory.CreateQueijo();
        Carne = ingredientFactory.CreateCarne();
    }
}

public class PremiumPizza {
    protected override Pizza CreatePizza(string sabor) {
        Pizza pizza;
        IPizzaIngredientFactory ingredientFactory = new PremiumPizzaIngredientFactory();
        switch (sabor) {
        case "Portuguesa":
            pizza = new Portuguesa(ingredientFactory);
            pizza.Nome = "Pizza Premium Portuguesa";
            break;
        case "Calabreza":
            pizza = new Calabreza(ingredientFactory);
            pizza.Nome = "Pizza Premium Calabreza";
            break;
        }
        return pizza;
    }
}

I put in the Github for future reference.

  • 1

    thanks for the answer. I understood the Simple Factory but I could not understand the other two, maybe because there is code missing. But my question was to know more when one is appropriate than the other. When I’m programming I try to isolate the object instances, creating Factories, but I always do the simple Factory because I can’t understand the motivation of the Factory method and Abstract Factory... then my doubt was more about the different motivations than how the Coda

  • 1

    I can try to improve, but I put these examples up to understand in practice when it is used. In fact the latter is more difficult to understand, the Method Factory is very simple too, I will try for something else, but it is what is written, it is used when you need to build the object in a specific way and you do not want to keep repeating all the code every time you want to create it. Maybe it’s hard to understand why he’s too simple and everyone expects something complicated. Simple Factory is the easiest to use, but also the most poorly used.

  • 7

    When the person does not understand where it is to apply, it probably means that it is not p/apply. It is the need that must make the search for the pattern, not the pattern seek a need.

  • 1

    I share a different opinion. I think it is acceptable that one does not understand where it is to apply a pattern because they are complex and require a deep mastery of object orientation that takes a long time to acquire. So, the situation may be there, but he doesn’t know that you can apply a pattern in that situation because he doesn’t master the pattern or the language. In my view, it is not always that a pattern is applied when it suits you. But anyway, it’s very good that we have different opinions because it enriches the forum and encourages other readers to think and criticize.

4

This answer is a junction of Vinicius Thiengo’s articles on Simple Factory, Factory Method and Abstract Factory.

Generally all Factory standards (Simple Factory, Factory Method, Abstract Factory) encapsulate the creation of objects.

Simple Factory

Simple Factory allows interfaces to create objects without exposing the logical creation to the client.

Simple Factory is a good starting point to separate the creation of objects from their use, few classes are created and the pattern structure is quite simple. If your context allows you to isolate the way objects are created and you have to deal with only one object type, Simple Factory is an excellent way to solve the problem.

Although simple, there are situations where using the standard Simple Factory does not help much. A very clear sign that the standard is not being effective is when the factory class starts to grow and have various methods to create the same products in different ways. This might be a good time to apply other factory standards.

Factory Method

Factory Method defines an interface to create an object, but lets subclasses decide which class to instantiate.

Factory Method can be used when a class cannot anticipate the class of objects it creates or when the class wants its subclasses to specify the objects it creates. It can also be used when classes delegate responsibility to one of several auxiliary subclasses, and you want to locate the knowledge of which auxiliary subclass is the delegate.

Abstract Factory

Abstract Factory provides interface to create families of related or dependent objects without specifying their concrete classes.

The Abstract Factory can be used when a system must be independent of how its products are created, composed or represented and the system must be configured as a product of a family of multiple products. It can also be used when an object family is designed to be used together, and you need to ensure this restriction and when you want to provide a class library and want to reveal only its interfaces, not its implementations.

Remember that there is no better version of Factory, each fits more optimally in specific problems of software design. And that goes for any design standard.


References:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.