10
\$\begingroup\$

I know that there are many similar questions, but I don't understand most of those questions because I'm not sure if I know what a factory method pattern is.

So, after reading many examples over the web, I came up with the following simple classes.

Am I doing it correctly? If so...any improvements I can add?

abstract class Driveable
{
    abstract public function start();
    abstract public function stop();

}

class CoupeDriveable extends Driveable
{
    public function start()
    {
    }

    public function stop()
    {
    }
}

class MotorcycleDriveable extends Driveable
{
    public function start()
    {
    }

    public function stop()
    {
    }   
}

class SedanDriveable extends Driveable
{
    public function start()
    {
    }

    public function stop()
    {
    }   
}

class DriveableFactory
{
    static public function create($numberOfPeople){

        if( $numberOfPeople == 1 )
        {
            return new MotorcycleDriveable;
        }       
        elseif( $numberOfPeople == 2 )
        {
            return new CoupleDriveable;
        }
        elseif( $numberOfPeople >= 3 && $numberOfPeople < 4)
        {
            return SedanDriveable;
        }
    }
}


class App
{
    static public function getDriveableMachine($numberOfPeople)
    {
        return DriveableFactory::create($numberOfPeople);
    }
}


$DriveableMachine = App::getDriveableMachine(2);
$DriveableMachine->start();

Update: according to palacsint and serghei's valueable advices, I've updated my code.

abstract class DriveableFactory
{
    static public function create($numberOfPeople);
}

class CarDriveableFactory extends DriveableFactory
{
    static public function create($numberOfPeople){

        $products = array
        (
            1=>"MotorcycleDriveable",
            2=>"CoupeDriveable",
            3=>"SedanDriveable",
            4=>"SedanDriveable"
        );

        if( isset( $products[$numberOfPeople] ) )
        {
            return new $products[$numberOfPeople];
        }
        else
        {
            throw new Exception("unable to find a suitable drivable car");
        }


    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Now your create function returns a string instead of an object. Was this for the sake of simplication? You got the Factory Method right though. \$\endgroup\$ Sep 9, 2013 at 4:45

3 Answers 3

7
\$\begingroup\$

The essence of the Factory method Pattern is to "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."

If you insist on the above GoF definition there are two issues.

First, you should create a DriveableFactory interface and rename your DriveableFactory to (for example) CarDriveableFactory.

abstract class DriveableFactory
{
    static public function create($numberOfPeople);
}

class CarDriveableFactory extends DriveableFactory
{
    static public function create($numberOfPeople) { ... }
}

But your code is fine, if you don't need (don't have a reason) the abstract DriveableFactory interface do NOT add it to the code.

The second issue is that the create method should not be static. If it's static subclasses cannot override the create method.

Finally, the App class looks unnecessary. So, I'd write something like this:

DriveableFactory factory = new CarDriveableFactory();
$DriveableMachine = factory->getDriveableMachine(2);
$DriveableMachine->start();

Some small improvements:

3.5 is an allowed value? And 3.1415? If not consider changing

else if( $numberOfPeople >= 3 && $numberOfPeople < 4)

to

else if($numberOfPeople == 3 || $numberOfPeople == 4)

In the last line of the create() method I would throw an IllegalArgumentException (or a similar one in PHP) with the message "invalid value: " . $numberOfPeople.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Isn't this the Abstract Factory Pattern, and not the factory method pattern? \$\endgroup\$
    – simao
    Nov 7, 2011 at 17:17
  • \$\begingroup\$ @simao: you are correct, the moment palacsint extended a factory to anther factory, this became an example of Abstract Factory Pattern. Factory Method would have created classes that inherits from a factory that has static methods to return one type of subclass. \$\endgroup\$ Sep 9, 2013 at 4:43
4
\$\begingroup\$

I think is good implementation but you can reduce the multiple if else conditions I don't know the PHP I can write you as I implement in C# code in C# there is specific type Dictionary that represent key value pair collection and if in PHP exist some similar you can use it look at the foolwing code

    private Driveable Create(int numberOfPeople)
    {
        Dictionary<int, Driveable> registerDriveable = new Dictionary<int, Driveable>();
        registerDriveable.Add(1, new MotorcycleDriveable());
        registerDriveable.Add(2, new CoupeDriveable());
        registerDriveable.Add(3, new SedanDriveable());
        registerDriveable.Add(4, new SedanDriveable());
        // and then find in dictionary by key

        //this code return the  new CoupeDriveable()
        Driveable driveable = registerDriveable[numberOfPeople];
        return driveable;
    }

benefit of this solutions is when you will add anther type of Driveable you don't need to add additional if else only one line

registerDriveable.Add(10, new BusDriveable());
\$\endgroup\$
1
  • 1
    \$\begingroup\$ +1, it's also a good point, but it's worth notice that if creating the Driveable objects is slow the else if could be better. \$\endgroup\$
    – palacsint
    Nov 2, 2011 at 11:14
0
\$\begingroup\$

As simao pointed out in a comment, this is an example of the Factory Pattern--not the Factory Method Pattern. In fact, you usually subclass the factory to determine the class to instantiate rather than making that determination based on a parameter. Perhaps this example mixes in the Builder Pattern or another whose name I'm forgetting at the moment.

The factory pattern defines an interface for creating instances where the concrete implementations define how to create those instances and what dependencies they require. Interfaces are used here because the factory's create method is called by other classes.

While related, the factory method pattern differs in that an abstract class defines a protected create method that is called by the concrete subclasses--never externally. You can always replace the method-based pattern with an external factory to increase flexibility.

Here's a simple example of using the factory method pattern:

Abstract Factory

abstract class Race
{
    private $racers = array();

    public function __construct($numRacers) {
        for ($i = 0; $i < $numRacers; $i++) {
            $this->racers[] = $this->createRacer($i);
        }
    }

    protected abstract function createRacer($racerNum);

    public function startRace() { ... use $this->racers ... }
}

Concrete Factory Implementations

class MotorcycleRace extends Race
{
    protected function createRacer($racerNum) {
        return new MotorcycleRacer($racerNum);
    }
}

class DragsterRace extends Race
{
    protected function createRacer($racerNum) {
        return new DragsterRacer($racerNum);
    }
}

class FormulaOneRace extends Race
{
    protected function createRacer($racerNum) {
        return new FormulaOneRacer($racerNum);
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.