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:15

One situation where I personally find separate Factory classes to make sense is when the final object you are trying to create relies on several other objects. E.g, in PHP: Suppose you have a House object, which in turn has a Kitchen and a LivingRoom object, and the LivingRoom object has a TV object inside as well.

The simplest method to achieve this is having each object create their children on their construct method, but if the properties are relatively nested, when your House fails creating you will probably spend some time trying to isolate exactly what is failing.

The alternative is to do the following (dependency injection, if you like the fancy term):

$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);

Here if the process of creating a House fails there is only one place to look, but having to use this chunk every time one wants a new House is far from convenient. Enter the Factories:

class HouseFactory {
    public function create() {
        $TVObj = new TV($param1, $param2, $param3);
        $LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
        $KitchenroomObj = new Kitchen($param1, $param2);
        $HouseObj = new House($LivingroomObj, $KitchenroomObj);

        return $HouseObj;
    }
}

$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();

Thanks to the factory here the process of creating a House is abstracted (in that you don't need to create and set up every single dependency when you just want to create a House) and at the same time centralized which makes it easier to maintain. There are other reasons why using separate Factories can be beneficial (e.g. testability) but I find this specific use case to illustrate best how Factory classes can be useful.

查看更多
听够珍惜
3楼-- · 2019-01-01 12:16

I like thinking about design pattens in terms of my classes being 'people,' and the patterns are the ways that the people talk to each other.

So, to me the factory pattern is like a hiring agency. You've got someone that will need a variable number of workers. This person may know some info they need in the people they hire, but that's it.

So, when they need a new employee, they call the hiring agency and tell them what they need. Now, to actually hire someone, you need to know a lot of stuff - benefits, eligibility verification, etc. But the person hiring doesn't need to know any of this - the hiring agency handles all of that.

In the same way, using a Factory allows the consumer to create new objects without having to know the details of how they're created, or what their dependencies are - they only have to give the information they actually want.

public interface IThingFactory
{
    Thing GetThing(string theString);
}

public class ThingFactory : IThingFactory
{
    public Thing GetThing(string theString)
    {
        return new Thing(theString, firstDependency, secondDependency);
    }
}

So, now the consumer of the ThingFactory can get a Thing, without having to know about the dependencies of the Thing, except for the string data that comes from the consumer.

查看更多
流年柔荑漫光年
4楼-- · 2019-01-01 12:16

I liken factories to the concept of libraries. For example you can have a library for working with numbers and another for working with shapes. You can store the functions of these libraries in logically named directories as Numbers or Shapes. These are generic types that could include integers, floats, dobules, longs or rectangles, circles, triangles, pentagons in the case of shapes.

The factory petter uses polymorphism, dependency injection and Inversion of control.

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

So let's say that you are building an Operating System or Framework and you are building all the discrete components.

Here is a simple example of the concept of the Factory Pattern in PHP. I may not be 100% on all of it but it's intended to serve as a simple example. I am not an expert.

class NumbersFactory {
    public static function makeNumber( $type, $number ) {
        $numObject = null;
        $number = null;

        switch( $type ) {
            case 'float':
                $numObject = new Float( $number );
                break;
            case 'integer':
                $numObject = new Integer( $number );
                break;
            case 'short':
                $numObject = new Short( $number );
                break;
            case 'double':
                $numObject = new Double( $number );
                break;
            case 'long':
                $numObject = new Long( $number );
                break;
            default:
                $numObject = new Integer( $number );
                break;
        }

        return $numObject;
    }
}

/* Numbers interface */
abstract class Number {
    protected $number;

    public function __construct( $number ) {
        $this->number = $number;
    }

    abstract public function add();
    abstract public function subtract();
    abstract public function multiply();
    abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Integer Implementation */
class Integer extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Short Implementation */
class Short extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Double Implementation */
class Double extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}
/* Long Implementation */
class Long extends Number {
    public function add() {
        // implementation goes here
    }

    public function subtract() {
        // implementation goes here
    }

    public function multiply() {
        // implementation goes here
    }

    public function divide() {
        // implementation goes here
    }
}

$number = NumbersFactory::makeNumber( 'float', 12.5 );
查看更多
听够珍惜
5楼-- · 2019-01-01 12:18

Factory classes are more heavyweight, but give you certain advantages. In cases when you need to build your objects from multiple, raw data sources they allow you to encapsulate only the building logic (and maybe the aggregation of the data) in one place. There it can be tested in abstract without being concerned with the object interface.

I have found this a useful pattern, particularly where I am unable to replace and inadequate ORM and want to efficiently instantiate many objects from DB table joins or stored procedures.

查看更多
其实,你不懂
6楼-- · 2019-01-01 12:22

It is good idea to use factory methods inside object when:

  1. Object's class doesn't know what exact sub-classes it have to create
  2. Object's class is designed so that objects it creates were specified by sub-classes
  3. Object's class delegates its duties to auxiliary sub-classes and doesn't know what exact class will take these duties

It is good idea to use abstract factory class when:

  1. Your object shouldn't depend on how its inner objects are created and designed
  2. Group of linked objects should be used together and you need to serve this constraint
  3. Object should be configured by one of several possible families of linked objects that will be a part of your parent object
  4. It is required to share child objects showing interfaces only but not an implementation
查看更多
浮光初槿花落
7楼-- · 2019-01-01 12:22

AbstractFactory example.

    TypeImpl<String> type = new TypeImpl<>();
    type.addType("Condition");
    type.addType("Hazardous");

    AbstractTypeFactory<String, Tag> tags = new AbstractTypeFactory<String, Tag>(type) {

        @Override
        public Tag create(String string) {
            String tp = type.find(string);

            switch (tp) {
                case "Hazardous":
                    return new HazardousTag();
                case "Condition":
                    return new ConditionTag();
                default:
                    return null;
            }
        }
    };

    Tag tagHazardous = tags.create("Hazardous");
    Tag tagCondition = tags.create("Condition");

}
查看更多
登录 后发表回答