Simple factory and Factory Method Design pattern difference

三世轮回 提交于 2019-12-05 18:36:50

Your understanding actually is correct, just you need to note that every design pattern is made to solve at least one single issue, sometimes it could bring with it some other complexities or side effects, which means there is no perfect design pattern that could solve every problems.

For learning purposes you apply design patterns one by one (that makes the real power of design patterns sames to be shy or hiding), however in a real world context design patterns are mixed together (or even you can invent a new one :p) for the purpose of creating something that satisfy most your needs and becomes near to ideal, you can meet for example the Builder pattern mixed with Factory pattern or Factory pattern with Strategy pattern, or even the three of them mixed together...

For your case here I propose for example to use Factory Method Pattern together with Simple Factory Pattern combined with Dependency Injection Pattern to create something totally beautiful and at the same time satisfying the Open closed principal.

class ItemFactoryContainer() {

    private Map<String, ItemFactory> factories = new HashMap<>();

    public void register(String name, ItemFactory factory) {
        factories.put(name, factory);
    }

    public ItemFactory getFactory(String name) {
        return factories.get(name);
    }
}

public class ItemFactoryTest {

    public static void main(String...args) {

        ItemFactoryContainer factoryContainer = new ItemFactoryContainer();

        factoryContainer.register("choclate", new ChocolateFactory ());
        factoryContainer.register("cake", new CakeFactory ());
        factoryContainer.register("iceCream", new IceCreamFactory  ());

        Chocolate choclate = factoryContainer.getFactory("choclate").getItem();
        Cake cake = factoryContainer.getFactory("cake").getItem();
    }
}

Answers (by @Mouad EL Fakir and @François LEPORCQ) are about the static factory. That is your first part of the code.

There are two more flavors namely Factory Method and Abstract Factory)

Second part of your code is using CakeFactory and ChocolateFactory, you are trying to use Factory Method (though your naming suggests Abstract Factory). The usage of factory method getXXX() here is incorrect. The purpose of these patterns is different. In your code you are not achieving anything but increasing number of classes. (though increased number of classes and parallel hierarchies is documented as cost associated with Factories)

I have answered a similar questions recently see if those answers are helpful

Role of Creator in Factory Pattern

What are the real benefits of using the Abstract Factory in the following example, instead of the factory method?

I think in your example a factory seem useless because your Cake and Chocolate constructors don't need any args.

A factory is useful when you want to construct a complex object with many args to respect the DIP (Dependency Inversion Principle) and avoid embarrassing couplings.

In addition, your example seems to violate the LSP (Liskov Substitution Principle). Cake and Chocolate classes have nothing in common, and as evidence, your abstract super class is named Item which is a very generic name.

For me, with complex uncommon objects, the choice of one factory by class is better, and effectively respect the OCP (Open Closed Principle).

Your first example can be useful to instantiate classes which inherits the same superclass, but using your classes as arg and reflection (using java.lang.reflect) to call the constructor not just using String evaluation. (Your IDE is not able to autocomplete that) and in case of no match don't return null, Throw an IllegalArgumentException, it's more correct.

Like this :

import java.lang.reflect.Constructor;

public class SimpleItemFactory {
    public <T extends Item> T createItem(Class<? extends Item> itemClass) {
        try {
            // construct your dependencies here
            // and inject them in the getConstructor
            Constructor<? extends Item> constructor = itemClass.getConstructor();
            return (T)constructor.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
    }
}

and use it like this :

class Client {
    public static void main(String[] args) {
        SimpleItemFactory factory = new SimpleItemFactory();
        IceCream iceCream = factory.createItem(IceCream.class);
        System.out.println(iceCream);
        Cake cake = factory.createItem(Cake.class);
        System.out.println(cake);
        Chocolate chocolate = factory.createItem(Chocolate.class);
        System.out.println(chocolate);
    }
}

If you have no dependencies you can implement the createItem() method as static directly in your abstract Item class.

See this book, it's a great resource : Head First Design Patterns

OCP is just Open for extension Close for modification Principle. If you need to open for modification your factory to add a new class (a new case to manage in a switch or a if), no, your factory is not "OCP".

You sould'nt calculate a tax in a constructor, a constructor should just... construct an object.. You could use a pattern like strategy to have many taxesCalculator and inject them into a constructor, with an IOC (Inversion of Control) mechanism like dependencies injection or in a simple way with.....a factory (it's acceptable), but not with a simple static method in your class.

I'm sorry for my bad english, it's difficult for me to answer to a complex question like this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!