Design Patterns: Factory vs Factory method vs Abstract Factory

I was reading design patterns from a website

There I read about Factory, Factory method and Abstract factory but they are so confusing, am not clear on the definition. According to definitions

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 Method - Defines an interface for creating objects, but let subclasses to decide which class to instantiate and Refers to the newly created object through a common interface.

Abstract Factory - Offers the interface for creating a family of related objects, without explicitly specifying their classes.

I also looked the other stackoverflow threads regarding Abstract Factory vs Factory Method but the UML diagrams drawn there make my understanding even worse.

Can anyone please tell me

  • How are these three patterns different from each other?
  • When to use which?
  • And also if possible, any java examples related to these patterns?

  • All three Factory types do the same thing: They are a "smart constructor".

    Let's say you want to be able to create two kinds of Fruit: Apple and Orange.

    Factory

    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.
      }
    
    }
    

    Use case: Constructing an Apple or an Orange is a bit too complex to handle in the constructor for either.

    Factory Method

    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..
        <bla bla bla>
      }
    }
    

    ...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

    Abstract factory is normally used for things like dependency injection/strategy, when you want to be able to create a whole family of objects that need to be of "the same kind", and have some common base classes. Here's a vaguely fruit-related example. The use case here is that we want to make sure that we don't accidentally use an OrangePicker on an Apple. As long at we get our Fruit and Picker from the same factory, they will match.

    interface PlantFactory {
    
      Plant makePlant();
    
      Picker makePicker(); 
    
    }
    
    public class AppleFactory implements PlantFactory {
      Plant makePlant() {
        return new Apple();
      }
    
      Picker makePicker() {
        return new ApplePicker();
      }
    }
    
    public class OrangeFactory implements PlantFactory {
      Plant makePlant() {
        return new Orange();
      }
    
      Picker makePicker() {
        return new OrangePicker();
      }
    }
    

    Factory - Separate Factory class to create complex object.

    Ex: FruitFactory class to create object of Fruit

    class FruitFactory{
    
    public static Fruit getFruit(){...}
    
    }
    

    Factory Method - Instead of whole separate class for factory, just add one method in that class itself as a factory.

    Ex:

    Calendar.getInstance() (Java's Calendar)
    

    Abstract Factory Method - Factory of Factory

    Ex: Lets say we want to build factory for computer parts. So there are several types of computers like Laptop, Desktop, Server.

    So for each compter type we need factory. So we create one highlevel factory of factories like below

    ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.
    

    Now these 3 itself are again factories. (You will be dealing with PartFactory itself, but under the hood, there will be separate implementation based on what you provided in abstract factory)

      Interface-> PartFactory. getComputerPart(String s), 
    Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.
    
    Usage:
    new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)
    

    EDIT: edited to provide exact interfaces for Abstract Factory as per the objections in comments.


  • How are these three patterns different from each other?
  • Factory: Creates objects without exposing the instantiation logic to the client.

    Factory Method: Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses

    Abstract Factory: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

    AbstractFactory pattern uses composition to delegate responsibility of creating object to another class while Factory method design pattern uses inheritance and relies on derived class or sub class to create object

  • When to use which?
  • Factory: Client just need a class and does not care about which concrete implementation it is getting.

    Factory Method: Client doesn't know what concrete classes it will be required to create at runtime, but just wants to get a class that will do the job.

    AbstactFactory: When your system has to create multiple families of products or you want to provide a library of products without exposing the implementation details.

    Abstract Factory classes are often implemented with Factory Method. Factory Methods are usually called within Template Methods.

  • And also if possible, any java examples related to these patterns?
  • Factory and FactoryMethod

    Intent:

    Define an interface for creating an object, but let sub classes decide which class to instantiate. Factory Method lets a class defer instantiation to sub classes.

    UML diagram:

    Product: It defines an interface of the objects the Factory method creates.

    ConcreteProduct: Implements Product interface

    Creator: Declares the Factory method

    ConcreateCreator: Implements the Factory method to return an instance of a ConcreteProduct

    Problem statement: Create a Factory of Games by using Factory Methods, which defines the game interface.

    Code snippet:

    import java.util.HashMap;
    
    
    /* Product interface as per UML diagram */
    interface Game{
        /* createGame is a complex method, which executes a sequence of game steps */
        public void createGame();
    }
    
    /* ConcreteProduct implementation as per UML diagram */
    class Chess implements Game{
        public Chess(){
            createGame();
        }
        public void createGame(){
            System.out.println("---------------------------------------");
            System.out.println("Create Chess game");
            System.out.println("Opponents:2");
            System.out.println("Define 64 blocks");
            System.out.println("Place 16 pieces for White opponent");
            System.out.println("Place 16 pieces for Black opponent");
            System.out.println("Start Chess game");
            System.out.println("---------------------------------------");
        }
    }
    class Checkers implements Game{
        public Checkers(){
            createGame();
        }
        public void createGame(){
            System.out.println("---------------------------------------");
            System.out.println("Create Checkers game");
            System.out.println("Opponents:2 or 3 or 4 or 6");
            System.out.println("For each opponent, place 10 coins");
            System.out.println("Start Checkers game");
            System.out.println("---------------------------------------");
        }
    }
    class Ludo implements Game{
        public Ludo(){
            createGame();
        }
        public void createGame(){
            System.out.println("---------------------------------------");
            System.out.println("Create Ludo game");
            System.out.println("Opponents:2 or 3 or 4");
            System.out.println("For each opponent, place 4 coins");
            System.out.println("Create two dices with numbers from 1-6");
            System.out.println("Start Ludo game");
            System.out.println("---------------------------------------");
        }
    }
    
    /* Creator interface as per UML diagram */
    interface IGameFactory {
        public Game getGame(String gameName);
    }
    
    /* ConcreteCreator implementation as per UML diagram */
    class GameFactory implements IGameFactory {
    
        HashMap<String,Game> games = new HashMap<String,Game>();
        /*  
            Since Game Creation is complex process, we don't want to create game using new operator every time.
            Instead we create Game only once and store it in Factory. When client request a specific game, 
            Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
        */
    
        public GameFactory(){
    
            games.put(Chess.class.getName(),new Chess());
            games.put(Checkers.class.getName(),new Checkers());
            games.put(Ludo.class.getName(),new Ludo());        
        }
        public Game getGame(String gameName){
            return games.get(gameName);
        }
    }
    
    public class NonStaticFactoryDemo{
        public static void main(String args[]){
            if ( args.length < 1){
                System.out.println("Usage: java FactoryDemo gameName");
                return;
            }
    
            GameFactory factory = new GameFactory();
            Game game = factory.getGame(args[0]);
            System.out.println("Game="+game.getClass().getName());
        }
    }
    

    output:

    java NonStaticFactoryDemo Chess
    ---------------------------------------
    Create Chess game
    Opponents:2
    Define 64 blocks
    Place 16 pieces for White opponent
    Place 16 pieces for Black opponent
    Start Chess game
    ---------------------------------------
    ---------------------------------------
    Create Checkers game
    Opponents:2 or 3 or 4 or 6
    For each opponent, place 10 coins
    Start Checkers game
    ---------------------------------------
    ---------------------------------------
    Create Ludo game
    Opponents:2 or 3 or 4
    For each opponent, place 4 coins
    Create two dices with numbers from 1-6
    Start Ludo game
    ---------------------------------------
    Game=Chess
    

    This example shows a Factory class by implementing a FactoryMethod .

  • Game is the interface for all type of games. It defines complex method: createGame()

  • Chess, Ludo, Checkers are different variants of games, which provide implementation to createGame()

  • public Game getGame(String gameName) is FactoryMethod in IGameFactory class

  • GameFactory pre-creates different type of games in constructor. It implements IGameFactory factory method.

  • game Name is passed as command line argument to NotStaticFactoryDemo

  • getGame in GameFactory accepts a game name and returns corresponding Game object.

  • Comparison with other creational patterns:

  • Design start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed

  • Abstract Factory classes are often implemented with Factory Methods , but they can also be implemented using Prototype

  • References for further reading: Sourcemaking design-patterns

    链接地址: http://www.djcxy.com/p/50116.html

    上一篇: 工厂,抽象工厂和工厂方法

    下一篇: 设计模式:工厂vs工厂方法与抽象工厂