refactored Factory Method pattern

This commit is contained in:
Dominik Liebler
2018-06-15 18:18:26 +02:00
parent f6d845e59e
commit bca6af02c0
27 changed files with 201 additions and 1198 deletions

View File

@@ -1,16 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class Bicycle implements VehicleInterface
{
/**
* @var string
*/
private $color;
public function setColor(string $rgb)
{
$this->color = $rgb;
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class CarFerrari implements VehicleInterface
{
/**
* @var string
*/
private $color;
public function setColor(string $rgb)
{
$this->color = $rgb;
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class CarMercedes implements VehicleInterface
{
/**
* @var string
*/
private $color;
public function setColor(string $rgb)
{
$this->color = $rgb;
}
public function addAMGTuning()
{
// do additional tuning here
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
abstract class FactoryMethod
{
const CHEAP = 'cheap';
const FAST = 'fast';
abstract protected function createVehicle(string $type): VehicleInterface;
public function create(string $type): VehicleInterface
{
$obj = $this->createVehicle($type);
$obj->setColor('black');
return $obj;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class FileLogger implements Logger
{
/**
* @var string
*/
private $filePath;
public function __construct(string $filePath)
{
$this->filePath = $filePath;
}
public function log(string $message)
{
file_put_contents($this->filePath, $message . PHP_EOL, FILE_APPEND);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class FileLoggerFactory implements LoggerFactory
{
/**
* @var string
*/
private $filePath;
public function __construct(string $filePath)
{
$this->filePath = $filePath;
}
public function createLogger(): Logger
{
return new FileLogger($this->filePath);
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class GermanFactory extends FactoryMethod
{
protected function createVehicle(string $type): VehicleInterface
{
switch ($type) {
case parent::CHEAP:
return new Bicycle();
case parent::FAST:
$carMercedes = new CarMercedes();
// we can specialize the way we want some concrete Vehicle since we know the class
$carMercedes->addAMGTuning();
return $carMercedes;
default:
throw new \InvalidArgumentException("$type is not a valid vehicle");
}
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class ItalianFactory extends FactoryMethod
{
protected function createVehicle(string $type): VehicleInterface
{
switch ($type) {
case parent::CHEAP:
return new Bicycle();
case parent::FAST:
return new CarFerrari();
default:
throw new \InvalidArgumentException("$type is not a valid vehicle");
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
interface Logger
{
public function log(string $message);
}

View File

@@ -0,0 +1,8 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
interface LoggerFactory
{
public function createLogger(): Logger;
}

View File

@@ -5,12 +5,12 @@ Purpose
-------
The good point over the SimpleFactory is you can subclass it to
implement different ways to create objects
implement different ways to create objects.
For simple case, this abstract class could be just an interface
For simple cases, this abstract class could be just an interface.
This pattern is a "real" Design Pattern because it achieves the
"Dependency Inversion Principle" a.k.a the "D" in S.O.L.I.D principles.
Dependency Inversion principle a.k.a the "D" in SOLID principles.
It means the FactoryMethod class depends on abstractions, not concrete
classes. This is the real trick compared to SimpleFactory or
@@ -28,45 +28,39 @@ Code
You can also find this code on `GitHub`_
FactoryMethod.php
Logger.php
.. literalinclude:: FactoryMethod.php
.. literalinclude:: Logger.php
:language: php
:linenos:
ItalianFactory.php
StdoutLogger.php
.. literalinclude:: ItalianFactory.php
.. literalinclude:: StdoutLogger.php
:language: php
:linenos:
GermanFactory.php
FileLogger.php
.. literalinclude:: GermanFactory.php
.. literalinclude:: FileLogger.php
:language: php
:linenos:
VehicleInterface.php
LoggerFactory.php
.. literalinclude:: VehicleInterface.php
.. literalinclude:: LoggerFactory.php
:language: php
:linenos:
CarMercedes.php
StdoutLoggerFactory.php
.. literalinclude:: CarMercedes.php
.. literalinclude:: StdoutLoggerFactory.php
:language: php
:linenos:
CarFerrari.php
FileLoggerFactory.php
.. literalinclude:: CarFerrari.php
:language: php
:linenos:
Bicycle.php
.. literalinclude:: Bicycle.php
.. literalinclude:: FileLoggerFactory.php
:language: php
:linenos:

View File

@@ -0,0 +1,11 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLogger implements Logger
{
public function log(string $message)
{
echo $message;
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
class StdoutLoggerFactory implements LoggerFactory
{
public function createLogger(): Logger
{
return new StdoutLogger();
}
}

View File

@@ -2,54 +2,27 @@
namespace DesignPatterns\Creational\FactoryMethod\Tests;
use DesignPatterns\Creational\FactoryMethod\Bicycle;
use DesignPatterns\Creational\FactoryMethod\CarFerrari;
use DesignPatterns\Creational\FactoryMethod\CarMercedes;
use DesignPatterns\Creational\FactoryMethod\FactoryMethod;
use DesignPatterns\Creational\FactoryMethod\GermanFactory;
use DesignPatterns\Creational\FactoryMethod\ItalianFactory;
use DesignPatterns\Creational\FactoryMethod\FileLogger;
use DesignPatterns\Creational\FactoryMethod\FileLoggerFactory;
use DesignPatterns\Creational\FactoryMethod\StdoutLogger;
use DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory;
use PHPUnit\Framework\TestCase;
class FactoryMethodTest extends TestCase
{
public function testCanCreateCheapVehicleInGermany()
public function testCanCreateStdoutLogging()
{
$factory = new GermanFactory();
$result = $factory->create(FactoryMethod::CHEAP);
$loggerFactory = new StdoutLoggerFactory();
$logger = $loggerFactory->createLogger();
$this->assertInstanceOf(Bicycle::class, $result);
$this->assertInstanceOf(StdoutLogger::class, $logger);
}
public function testCanCreateFastVehicleInGermany()
public function testCanCreateFileLogging()
{
$factory = new GermanFactory();
$result = $factory->create(FactoryMethod::FAST);
$loggerFactory = new FileLoggerFactory(sys_get_temp_dir());
$logger = $loggerFactory->createLogger();
$this->assertInstanceOf(CarMercedes::class, $result);
}
public function testCanCreateCheapVehicleInItaly()
{
$factory = new ItalianFactory();
$result = $factory->create(FactoryMethod::CHEAP);
$this->assertInstanceOf(Bicycle::class, $result);
}
public function testCanCreateFastVehicleInItaly()
{
$factory = new ItalianFactory();
$result = $factory->create(FactoryMethod::FAST);
$this->assertInstanceOf(CarFerrari::class, $result);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage spaceship is not a valid vehicle
*/
public function testUnknownType()
{
(new ItalianFactory())->create('spaceship');
$this->assertInstanceOf(FileLogger::class, $logger);
}
}

View File

@@ -1,8 +0,0 @@
<?php
namespace DesignPatterns\Creational\FactoryMethod;
interface VehicleInterface
{
public function setColor(string $rgb);
}

View File

@@ -1,51 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<Diagram>
<ID>PHP</ID>
<OriginalElement>\DesignPatterns\Creational\FactoryMethod\GermanFactory</OriginalElement>
<OriginalElement>\DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory</OriginalElement>
<nodes>
<node x="87.0" y="242.0">\DesignPatterns\Creational\FactoryMethod\FactoryMethod</node>
<node x="164.0" y="112.0">\DesignPatterns\Creational\FactoryMethod\Bicycle</node>
<node x="308.0" y="112.0">\DesignPatterns\Creational\FactoryMethod\CarFerrari</node>
<node x="194.0" y="365.0">\DesignPatterns\Creational\FactoryMethod\ItalianFactory</node>
<node x="0.0" y="101.0">\DesignPatterns\Creational\FactoryMethod\CarMercedes</node>
<node x="0.0" y="365.0">\DesignPatterns\Creational\FactoryMethod\GermanFactory</node>
<node x="157.0" y="0.0">\DesignPatterns\Creational\FactoryMethod\VehicleInterface</node>
<node x="119.25" y="0.0">\DesignPatterns\Creational\FactoryMethod\LoggerFactory</node>
<node x="220.0" y="124.0">\DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory</node>
<node x="183.0" y="-160.0">\DesignPatterns\Creational\FactoryMethod\FileLogger</node>
<node x="0.0" y="101.0">\DesignPatterns\Creational\FactoryMethod\FileLoggerFactory</node>
<node x="8.0" y="-137.0">\DesignPatterns\Creational\FactoryMethod\StdoutLogger</node>
<node x="106.75" y="-261.0">\DesignPatterns\Creational\FactoryMethod\Logger</node>
</nodes>
<notes />
<edges>
<edge source="\DesignPatterns\Creational\FactoryMethod\GermanFactory" target="\DesignPatterns\Creational\FactoryMethod\FactoryMethod">
<edge source="\DesignPatterns\Creational\FactoryMethod\StdoutLogger" target="\DesignPatterns\Creational\FactoryMethod\Logger">
<point x="0.0" y="-25.5" />
<point x="87.0" y="340.0" />
<point x="135.5" y="340.0" />
<point x="-48.5" y="36.5" />
<point x="85.5" y="-185.0" />
<point x="145.5" y="-185.0" />
<point x="-38.75" y="25.5" />
</edge>
<edge source="\DesignPatterns\Creational\FactoryMethod\CarMercedes" target="\DesignPatterns\Creational\FactoryMethod\VehicleInterface">
<point x="0.0" y="-48.0" />
<point x="72.0" y="76.0" />
<point x="180.0" y="76.0" />
<point x="-46.0" y="25.5" />
<edge source="\DesignPatterns\Creational\FactoryMethod\FileLogger" target="\DesignPatterns\Creational\FactoryMethod\Logger">
<point x="0.0" y="-48.5" />
<point x="283.0" y="-185.0" />
<point x="223.0" y="-185.0" />
<point x="38.75" y="25.5" />
</edge>
<edge source="\DesignPatterns\Creational\FactoryMethod\Bicycle" target="\DesignPatterns\Creational\FactoryMethod\VehicleInterface">
<point x="0.0" y="-37.0" />
<point x="0.0" y="25.5" />
</edge>
<edge source="\DesignPatterns\Creational\FactoryMethod\ItalianFactory" target="\DesignPatterns\Creational\FactoryMethod\FactoryMethod">
<edge source="\DesignPatterns\Creational\FactoryMethod\StdoutLoggerFactory" target="\DesignPatterns\Creational\FactoryMethod\LoggerFactory">
<point x="0.0" y="-25.5" />
<point x="281.0" y="340.0" />
<point x="232.5" y="340.0" />
<point x="48.5" y="36.5" />
<point x="301.5" y="76.0" />
<point x="241.5" y="76.0" />
<point x="40.75" y="25.5" />
</edge>
<edge source="\DesignPatterns\Creational\FactoryMethod\CarFerrari" target="\DesignPatterns\Creational\FactoryMethod\VehicleInterface">
<point x="0.0" y="-37.0" />
<point x="370.0" y="76.0" />
<point x="272.0" y="76.0" />
<point x="46.0" y="25.5" />
<edge source="\DesignPatterns\Creational\FactoryMethod\FileLoggerFactory" target="\DesignPatterns\Creational\FactoryMethod\LoggerFactory">
<point x="0.0" y="-48.5" />
<point x="100.0" y="76.0" />
<point x="160.0" y="76.0" />
<point x="-40.75" y="25.5" />
</edge>
</edges>
<settings layout="Hierarchic Group" zoom="1.0" x="216.0" y="208.0" />
<SelectedNodes />
<settings layout="Hierarchic Group" zoom="1.0" x="375.0" y="60.5" />
<SelectedNodes>
<node>\DesignPatterns\Creational\FactoryMethod\FileLogger</node>
<node>\DesignPatterns\Creational\FactoryMethod\StdoutLogger</node>
<node>\DesignPatterns\Creational\FactoryMethod\Logger</node>
</SelectedNodes>
<Categories>
<Category>Fields</Category>
<Category>Constants</Category>
<Category>Constructors</Category>
<Category>Methods</Category>
</Categories>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB