Tuesday, April 28, 2015

Design Patterns: Factory vs Factory method vs Abstract Factory

Factory:

Creates objects without exposing the instantiation logic to the client and Refers to the newly created object through a common interface. Is a simplified version of Factory Method.


Factory is "fixed", in that you have just one implementation with no subclassing. In this case, you will have a class like this:
class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Factory Method :

Exposes a method for creating objects, allowing subclasses to control the actual creation process.

Factory method is generally used when you have some generic processing in a class, but want to vary which kind of fruit you actually use. So:
abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
     
  }
}
then you can reuse the common functionality in FruitPicker.pickFruit() by implementing a factory method in subclasses:
class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Abstract Factory :

Offers the interface for creating a family of related objects, without explicitly specifying their classes. The AbstractFactory defines the interface that all of the concrete factories will need to implement
AbstractFactory classes are often implemented with factory methods

First, we'll need to create our Window interface. Window is our AbstractProduct

1.//Our AbstractProduct
2.public interface Window
3.{
4. 
5.public void setTitle(String text);
6. 
7.public void repaint();
8.}
Let's create two implementations of the Window, as our ConcreteProducts. One for Microsoft Windows: 

01.//ConcreteProductA1
02.public class MSWindow implements Window
03.{
04.public void setTitle()
05.{
06.//MS Windows specific behaviour
07.}
08. 
09.public void repaint()
10.{
11.//MS Windows specific behaviour
12.}
13.}
And one for Mac OSX

01.//ConcreteProductA2
02.public class MacOSXWindow implements Window
03.{
04.public void setTitle()
05.{
06.//Mac OSX specific behaviour
07.}
08. 
09.public void repaint()
10.{
11.//Mac OSX specific behaviour
12.}
13.}
Now we need to provide our factories. First we'll define our AbstractFactory. For this example, let's say they just create Windows: 

1.//AbstractFactory
2.public interface AbstractWidgetFactory
3.{
4.public Window createWindow();
5.}
Next we need to provide ConcreteFactory implementations of these factories for our two operating systems. First for MS Windows:


01.//ConcreteFactory1
02.public class MsWindowsWidgetFactory
03.{
04.//create an MSWindow
05.public Window createWindow()
06.{
07.MSWindow window = new MSWindow();  
08.return window;
09.}
10.}
And for MacOSX: 

01.//ConcreteFactory2
02.public class MacOSXWidgetFactory
03.{
04.//create a MacOSXWindow
05.public Window createWindow()
06.{
07.MacOSXWindow window = new MacOSXWindow();  
08.return window;
09.}
10.}
Finally we need a client to take advantage of all this functionality. 

01.//Client
02.public class GUIBuilder
03.{
04.public void buildWindow(AbstractWidgetFactory widgetFactory)
05.{
06.Window window = widgetFactory.createWindow();  
07.window.setTitle("New Window");
08.}
09.}
Of course, we need some way to specify which type of AbstractWidgetFactory to our GUIBuilder. This is usually done with a switch statement similar to the code below:

01.public class Main{
02.public static void main(String[] args)  
03.{
04.GUIBuilder builder = new GUIBuilder();
05.AbstractWidgetFactory widgetFactory = null;
06.//check what platform we're on
07.if(Platform.currentPlatform()=="MACOSX")
08.{
09.widgetFactory  = new MacOSXWidgetFactory();
10.}
11.else
12.{
13.widgetFactory  = new MsWindowsWidgetFactory();
14.}
15.builder.buildWindow(widgetFactory);
16.}
17.}

Note: content of this post is extracted from http://www.stackoverflow.com and http://java.dzone.com