Factory Pattern. When to use factory methods?

2019-01-01 11:26发布

When is it a good idea to use factory methods within an object instead of a Factory class?

16条回答
浪荡孟婆
2楼-- · 2019-01-01 12:04

According to sourcemaking website, it's intentions are:

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

  • Defining a "virtual" constructor.

  • The new operator considered harmful.

An example of how it can be used:

abstract class AbstractFactoryMethod {
    abstract function makePHPBook($param);
}

class OReillyFactoryMethod extends AbstractFactoryMethod
{
    function makePHPBook($param)
    {
        $book = NULL;  
        switch ($param) {
            case "us":
                $book = new OReillyPHPBook();
            break;
            // Other classes...
            case "other":
                $book = new SamsPHPBook();
            break;
            default:
                $book = new OReillyPHPBook();
            break;        
    }

    return $book;
}

And then the testing:

function testFactoryMethod($factoryMethodInstance)
{
    $phpUs = $factoryMethodInstance->makePHPBook("us");
    echo 'us php Author: '.$phpUs->getAuthor();
    echo 'us php Title: '.$phpUs->getTitle();
}

echo 'Testing OReillyFactoryMethod';
$factoryMethodInstance = new OReillyFactoryMethod();
testFactoryMethod($factoryMethodInstance);
查看更多
还给你的自由
3楼-- · 2019-01-01 12:07

It is important to clearly differentiate the idea behind using factory or factory method. Both are meant to address mutually exclusive different kind of object creation problems.

Let's be specific about "factory method":

First thing is that, when you are developing library or APIs which in turn will be used for further application development, then factory method is one of the best selections for creation pattern. Reason behind; We know that when to create an object of required functionality(s) but type of object will remain undecided or it will be decided ob dynamic parameters being passed.

Now the point is, approximately same can be achieved by using factory pattern itself but one huge drawback will introduce into the system if factory pattern will be used for above highlighted problem, it is that your logic of crating different objects(sub classes objects) will be specific to some business condition so in future when you need to extend your library's functionality for other platforms(In more technically, you need to add more sub classes of basic interface or abstract class so factory will return those objects also in addition to existing one based on some dynamic parameters) then every time you need to change(extend) the logic of factory class which will be costly operation and not good from design perspective. On the other side, if "factory method" pattern will be used to perform the same thing then you just need to create additional functionality(sub classes) and get it registered dynamically by injection which doesn't require changes in your base code.

interface Deliverable 
{
    /*********/
}

abstract class DefaultProducer 
{

    public void taskToBeDone() 
    {   
        Deliverable deliverable = factoryMethodPattern();
    }
    protected abstract Deliverable factoryMethodPattern();
}

class SpecificDeliverable implements Deliverable 
{
 /***SPECIFIC TASK CAN BE WRITTEN HERE***/
}

class SpecificProducer extends DefaultProducer 
{
    protected Deliverable factoryMethodPattern() 
    {
        return new SpecificDeliverable();
    }
}

public class MasterApplicationProgram 
{
    public static void main(String arg[]) 
    {
        DefaultProducer defaultProducer = new SpecificProducer();
        defaultProducer.taskToBeDone();
    }
}
查看更多
旧时光的记忆
4楼-- · 2019-01-01 12:09

UML from

enter image description here

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(){

    }
    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(){

    }
    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(){

    }
    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]);
        if ( game != null ){                    
            game.createGame();
            System.out.println("Game="+game.getClass().getName());
        }else{
            System.out.println(args[0]+  " Game does not exists in factory");
        }           
    }
}

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
---------------------------------------
Game=Chess

This example shows a Factory class by implementing a FactoryMethod.

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

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

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

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

  5. game Name is passed as command line argument to NotStaticFactoryDemo

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

Factory:

Creates objects without exposing the instantiation logic to the client.

FactoryMethod

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

Use case:

When to use: 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.

查看更多
与风俱净
5楼-- · 2019-01-01 12:11

It's really a matter of taste. Factory classes can be abstracted/interfaced away as necessary, whereas factory methods are lighter weight (and also tend to be testable, since they don't have a defined type, but they will require a well-known registration point, akin to a service locator but for locating factory methods).

查看更多
墨雨无痕
6楼-- · 2019-01-01 12:12

Consider a scenario when you have to design an Order and Customer class. For simplicity and initial requirements you do not feel need of factory for Order class and fill your application with many 'new Order()' statements. Things are working well.

Now a new requirement comes into picture that Order object cannot be instantiated without Customer association (new dependency). Now You have following considerations.

1- You create constructor overload which will work only for new implementations. (Not acceptable). 2- You change Order() signatures and change each and every invokation. (Not a good practice and real pain).

Instead If you have created a factory for Order Class you only have to change one line of code and you are good to go. I suggest Factory class for almost every aggregate association. Hope that helps.

查看更多
大哥的爱人
7楼-- · 2019-01-01 12:12

Any class deferring the object creation to its sub class for the object it needs to work with can be seen as an example of Factory pattern.

I have mentioned in detail in an another answer at https://stackoverflow.com/a/49110001/504133

查看更多
登录 后发表回答