I am learning design patterns newly & I am trying to understand the difference between Simple Factory & Factory Method Pattern. First I want to clear that , I tried reading lot of articles from Stack-overflow and other sites regarding the same but that doesn't helped me.
Here is my question: Lets consider I have a product hierarchy as shown below:
I have written a simple Factory class as shown below
public class SimpleItemFactory {
static Item getItem(String type) {
if(type.equals("Cake")) {
return new Cake();
}else if(type.equals("Chocolate")) {
return new Chocolate();
}else {
return null;
}
}
}
so now I have all the object creation in one place , so if tomorrow any changes occurs[Like constructor needs one parameter] we need to change in only one place. But it breaks OPEN CLOSED principle as if tomorrow we add more item we need to change getItem() methods if condition. So we go for Factory Method Pattern
We create Factory class as shown below:
public abstract class ItemFactory {
abstract Item getItem();
}
class CakeFactory extends ItemFactory {
@Override
Item getItem() {
return new Cake();
}
}
class ChocolateFactory extends ItemFactory {
@Override
Item getItem() {
return new Chocolate();
}
}
class Client{
public static void main(String[] args) {
Item chocolate = new ChocolateFactory().getItem();
System.out.println(chocolate);
}
}
Now when the client want to add new Item called IceCream, they just create new Factory called IceCreamFactory and create IceCream from that as shown below:
class IceCreamFactory extends ItemFactory{
@Override
Item getItem() {
return new IceCream();
}
}
class Client{
public static void main(String[] args) {
Item iceCream = new IceCreamFactory().getItem();
System.out.println(iceCream);
}
}
Is my understanding correct? We satisfied Open closed principle here, but for each product(Item) we need one Factory class, does not it become manageable nightmare?
NOTE: Article I was referring https://www.codeproject.com/Articles/1135918/Factory-Patterns-Factory-Method-Pattern?msg=5380215#xx5380215xx
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
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.
来源:https://stackoverflow.com/questions/46501200/simple-factory-and-factory-method-design-pattern-difference