mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-08-03 13:37:27 +02:00
PHP7 TemplateMethod
This commit is contained in:
@@ -2,16 +2,10 @@
|
|||||||
|
|
||||||
namespace DesignPatterns\Behavioral\TemplateMethod;
|
namespace DesignPatterns\Behavioral\TemplateMethod;
|
||||||
|
|
||||||
/**
|
|
||||||
* BeachJourney is vacation at the beach.
|
|
||||||
*/
|
|
||||||
class BeachJourney extends Journey
|
class BeachJourney extends Journey
|
||||||
{
|
{
|
||||||
/**
|
protected function enjoyVacation(): string
|
||||||
* prints what to do to enjoy your vacation.
|
|
||||||
*/
|
|
||||||
protected function enjoyVacation()
|
|
||||||
{
|
{
|
||||||
echo "Swimming and sun-bathing\n";
|
return "Swimming and sun-bathing";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,15 @@
|
|||||||
|
|
||||||
namespace DesignPatterns\Behavioral\TemplateMethod;
|
namespace DesignPatterns\Behavioral\TemplateMethod;
|
||||||
|
|
||||||
/**
|
|
||||||
* CityJourney is a journey in a city.
|
|
||||||
*/
|
|
||||||
class CityJourney extends Journey
|
class CityJourney extends Journey
|
||||||
{
|
{
|
||||||
/**
|
protected function enjoyVacation(): string
|
||||||
* prints what to do in your journey to enjoy vacation.
|
|
||||||
*/
|
|
||||||
protected function enjoyVacation()
|
|
||||||
{
|
{
|
||||||
echo "Eat, drink, take photos and sleep\n";
|
return "Eat, drink, take photos and sleep";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buyGift(): string
|
||||||
|
{
|
||||||
|
return "Buy a gift";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,11 @@ namespace DesignPatterns\Behavioral\TemplateMethod;
|
|||||||
|
|
||||||
abstract class Journey
|
abstract class Journey
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $thingsToDo = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the public service provided by this class and its subclasses.
|
* This is the public service provided by this class and its subclasses.
|
||||||
* Notice it is final to "freeze" the global behavior of algorithm.
|
* Notice it is final to "freeze" the global behavior of algorithm.
|
||||||
@@ -12,46 +17,49 @@ abstract class Journey
|
|||||||
*/
|
*/
|
||||||
final public function takeATrip()
|
final public function takeATrip()
|
||||||
{
|
{
|
||||||
$this->buyAFlight();
|
$this->thingsToDo[] = $this->buyAFlight();
|
||||||
$this->takePlane();
|
$this->thingsToDo[] = $this->takePlane();
|
||||||
$this->enjoyVacation();
|
$this->thingsToDo[] = $this->enjoyVacation();
|
||||||
$this->buyGift();
|
$buyGift = $this->buyGift();
|
||||||
$this->takePlane();
|
|
||||||
|
if ($buyGift !== null) {
|
||||||
|
$this->thingsToDo[] = $buyGift;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->thingsToDo[] = $this->takePlane();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method must be implemented, this is the key-feature of this pattern.
|
* This method must be implemented, this is the key-feature of this pattern.
|
||||||
*/
|
*/
|
||||||
abstract protected function enjoyVacation();
|
abstract protected function enjoyVacation(): string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is also part of the algorithm but it is optional.
|
* This method is also part of the algorithm but it is optional.
|
||||||
* This is an "adapter" (do not confuse with the Adapter pattern, not related)
|
* You can override it only if you need to
|
||||||
* You can override it only if you need to.
|
*
|
||||||
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
protected function buyGift()
|
protected function buyGift()
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buyAFlight(): string
|
||||||
|
{
|
||||||
|
return 'Buy a flight ticket';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function takePlane(): string
|
||||||
|
{
|
||||||
|
return 'Taking the plane';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will be unknown by subclasses (better).
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
private function buyAFlight()
|
public function getThingsToDo(): array
|
||||||
{
|
{
|
||||||
echo "Buying a flight\n";
|
return $this->thingsToDo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclasses will get access to this method but cannot override it and
|
|
||||||
* compromise this algorithm (warning : cause of cyclic dependencies).
|
|
||||||
*/
|
|
||||||
final protected function takePlane()
|
|
||||||
{
|
|
||||||
echo "Taking the plane\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// A note regarding the keyword "final" : don't use it when you start coding :
|
|
||||||
// add it after you narrow and know exactly what change and what remain unchanged
|
|
||||||
// in this algorithm.
|
|
||||||
// [abstract] x [3 access] x [final] = 12 combinations, it can be hard !
|
|
||||||
}
|
}
|
||||||
|
@@ -4,40 +4,33 @@ namespace DesignPatterns\Behavioral\TemplateMethod\Tests;
|
|||||||
|
|
||||||
use DesignPatterns\Behavioral\TemplateMethod;
|
use DesignPatterns\Behavioral\TemplateMethod;
|
||||||
|
|
||||||
/**
|
|
||||||
* JourneyTest tests all journeys.
|
|
||||||
*/
|
|
||||||
class JourneyTest extends \PHPUnit_Framework_TestCase
|
class JourneyTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
public function testBeach()
|
public function testCanGetOnVacationOnTheBeach()
|
||||||
{
|
{
|
||||||
$journey = new TemplateMethod\BeachJourney();
|
$beachJourney = new TemplateMethod\BeachJourney();
|
||||||
$this->expectOutputRegex('#sun-bathing#');
|
$beachJourney->takeATrip();
|
||||||
$journey->takeATrip();
|
|
||||||
|
$this->assertEquals(
|
||||||
|
['Buy a flight ticket', 'Taking the plane', 'Swimming and sun-bathing', 'Taking the plane'],
|
||||||
|
$beachJourney->getThingsToDo()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCity()
|
public function testCanGetOnAJourneyToACity()
|
||||||
{
|
{
|
||||||
$journey = new TemplateMethod\CityJourney();
|
$beachJourney = new TemplateMethod\CityJourney();
|
||||||
$this->expectOutputRegex('#drink#');
|
$beachJourney->takeATrip();
|
||||||
$journey->takeATrip();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$this->assertEquals(
|
||||||
* How to test an abstract template method with PHPUnit.
|
[
|
||||||
*/
|
'Buy a flight ticket',
|
||||||
public function testLasVegas()
|
'Taking the plane',
|
||||||
{
|
'Eat, drink, take photos and sleep',
|
||||||
$journey = $this->getMockForAbstractClass('DesignPatterns\Behavioral\TemplateMethod\Journey');
|
'Buy a gift',
|
||||||
$journey->expects($this->once())
|
'Taking the plane'
|
||||||
->method('enjoyVacation')
|
],
|
||||||
->will($this->returnCallback(array($this, 'mockUpVacation')));
|
$beachJourney->getThingsToDo()
|
||||||
$this->expectOutputRegex('#Las Vegas#');
|
);
|
||||||
$journey->takeATrip();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mockUpVacation()
|
|
||||||
{
|
|
||||||
echo "Fear and loathing in Las Vegas\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,24 +3,24 @@
|
|||||||
<ID>PHP</ID>
|
<ID>PHP</ID>
|
||||||
<OriginalElement>\DesignPatterns\Behavioral\TemplateMethod\BeachJourney</OriginalElement>
|
<OriginalElement>\DesignPatterns\Behavioral\TemplateMethod\BeachJourney</OriginalElement>
|
||||||
<nodes>
|
<nodes>
|
||||||
<node x="152.0" y="177.0">\DesignPatterns\Behavioral\TemplateMethod\CityJourney</node>
|
<node x="-18.0" y="234.0">\DesignPatterns\Behavioral\TemplateMethod\BeachJourney</node>
|
||||||
<node x="47.0" y="0.0">\DesignPatterns\Behavioral\TemplateMethod\Journey</node>
|
<node x="13.0" y="-3.0">\DesignPatterns\Behavioral\TemplateMethod\Journey</node>
|
||||||
<node x="0.0" y="177.0">\DesignPatterns\Behavioral\TemplateMethod\BeachJourney</node>
|
<node x="151.0" y="234.0">\DesignPatterns\Behavioral\TemplateMethod\CityJourney</node>
|
||||||
</nodes>
|
</nodes>
|
||||||
<notes />
|
<notes />
|
||||||
<edges>
|
<edges>
|
||||||
<edge source="\DesignPatterns\Behavioral\TemplateMethod\CityJourney" target="\DesignPatterns\Behavioral\TemplateMethod\Journey">
|
|
||||||
<point x="0.0" y="-23.5" />
|
|
||||||
<point x="218.0" y="152.0" />
|
|
||||||
<point x="189.5" y="152.0" />
|
|
||||||
<point x="47.5" y="63.5" />
|
|
||||||
</edge>
|
|
||||||
<edge source="\DesignPatterns\Behavioral\TemplateMethod\BeachJourney" target="\DesignPatterns\Behavioral\TemplateMethod\Journey">
|
<edge source="\DesignPatterns\Behavioral\TemplateMethod\BeachJourney" target="\DesignPatterns\Behavioral\TemplateMethod\Journey">
|
||||||
<point x="0.0" y="-23.5" />
|
<point x="0.0" y="-23.5" />
|
||||||
<point x="66.0" y="152.0" />
|
<point x="66.0" y="152.0" />
|
||||||
<point x="94.5" y="152.0" />
|
<point x="94.5" y="152.0" />
|
||||||
<point x="-47.5" y="63.5" />
|
<point x="-47.5" y="63.5" />
|
||||||
</edge>
|
</edge>
|
||||||
|
<edge source="\DesignPatterns\Behavioral\TemplateMethod\CityJourney" target="\DesignPatterns\Behavioral\TemplateMethod\Journey">
|
||||||
|
<point x="0.0" y="-23.5" />
|
||||||
|
<point x="218.0" y="152.0" />
|
||||||
|
<point x="189.5" y="152.0" />
|
||||||
|
<point x="47.5" y="63.5" />
|
||||||
|
</edge>
|
||||||
</edges>
|
</edges>
|
||||||
<settings layout="Hierarchic Group" zoom="1.0" x="142.0" y="112.0" />
|
<settings layout="Hierarchic Group" zoom="1.0" x="142.0" y="112.0" />
|
||||||
<SelectedNodes />
|
<SelectedNodes />
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 46 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 107 KiB |
Reference in New Issue
Block a user