An Army of Service Classes
Yay! We got rid of a flat function. Woh - not so fast: inside battle(),
we're calling a flat function: didJediDestroyShipUsingTheForce():
| // ... lines 1 - 2 | |
| class BattleManager | |
| { | |
| // ... lines 5 - 9 | |
| public function battle(Ship $ship1, $ship1Quantity, Ship $ship2, $ship2Quantity) | |
| { | |
| // ... lines 12 - 18 | |
| if (didJediDestroyShipUsingTheForce($ship1)) { | |
| // ... lines 20 - 23 | |
| } | |
| // ... lines 25 - 56 | |
| } | |
| } |
No bueno!
Refactoring to private Functions
This lives at the bottom of functions.php. In our app, this is only called
from inside battle(), and since it obviously relates to battles, let's
move it into BattleManager. Make it a private function:
| // ... lines 1 - 2 | |
| class BattleManager | |
| { | |
| // ... lines 5 - 58 | |
| private function didJediDestroyShipUsingTheForce(Ship $ship) | |
| { | |
| $jediHeroProbability = $ship->getJediFactor() / 100; | |
| return mt_rand(1, 100) <= ($jediHeroProbability*100); | |
| } | |
| } |
Why did I make it private? Well, do we need use this function from outside
of this class? No - the only code using it is up in battle(), so this is
a perfect candidate to be private.
Above in battle(), update the calls to be $this->didJediDestroyShipUsingTheForce().
The "force" of our app is happy again:
| // ... lines 1 - 2 | |
| class BattleManager | |
| { | |
| // ... lines 5 - 9 | |
| public function battle(Ship $ship1, $ship1Quantity, Ship $ship2, $ship2Quantity) | |
| { | |
| // ... lines 12 - 18 | |
| if ($this->didJediDestroyShipUsingTheForce($ship1)) { | |
| // ... lines 20 - 23 | |
| } | |
| if ($this->didJediDestroyShipUsingTheForce($ship2)) { | |
| // ... lines 26 - 29 | |
| } | |
| // ... lines 31 - 56 | |
| } | |
| // ... lines 58 - 64 | |
| } |
Now, if someday we did want to use this function from outside of BattleManager,
then we could change it to public. Ok, so why not just make everything
public - isn't that more flexible? Yes, but making this private
is nice: it means that if I want to change this function - add arguments
or even change what it returns - I know that the only code that will be
affected will be right inside this class. If it's public, who knows what
code I might break in my app?
Start with private, make it public only if you need. The same rule goes
for protected - something we'll talk about later with inheritance.
Let's make sure we didn't bust things. Refresh!
Yes!
Service 2: ShipLoader
In functions.php, only the flat get_ships() function remains. You guys
know what do to: move it into a class!
Should we move it into BattleManager? No - it doesn't relate to battles.
Instead, create a new class for this - how about ShipLoader:
| // ... lines 1 - 2 | |
| class ShipLoader | |
| { | |
| // ... lines 5 - 36 | |
| } |
Let's work our magic: go grab get_ships() and move it into ShipLoader.
Remove the old commented code and make the function public. Also, rename
it from get_ships() to getShips() - that's a more common naming standard
for methods in a class:
| // ... lines 1 - 2 | |
| class ShipLoader | |
| { | |
| public function getShips() | |
| { | |
| $ships = array(); | |
| $ship = new Ship('Jedi Starfighter'); | |
| // ... lines 10 - 33 | |
| return $ships; | |
| } | |
| } |
Yep, that's great! Now we need to update the code that calls this function.
But first, open functions.php and require the new ShipLoader.php:
| // ... lines 1 - 4 | |
| require_once __DIR__.'/lib/ShipLoader.php'; |
getShips() is used in battle.php and index.php - start there. To
call the method, create a $shipLoader variable and create a new ShipLoader()
object. Now, just $shipLoader->getShips():
| require __DIR__.'/functions.php'; | |
| $shipLoader = new ShipLoader(); | |
| $ships = $shipLoader->getShips(); | |
| // ... lines 6 - 119 |
Do the same thing in battle.php:
| require __DIR__.'/functions.php'; | |
| $shipLoader = new ShipLoader(); | |
| $ships = $shipLoader->getShips(); | |
| // ... lines 6 - 99 |
I think it's time to try it. Click to create a new battle. Looks pretty good.
Setup a new battle and, Engage. Ok! battle.php works too!
No More functions.php
AND, all the flat functions are gone! Object-orient all the things! So if
you look in functions.php, well, there aren't any functions here: just
require statements, and even those we'll get rid of eventually. To celebrate,
give this a more appropriate name: bootstrap.php. Update this in battle.php:
| require __DIR__.'/bootstrap.php'; | |
| // ... lines 3 - 99 |
and index.php:
| require __DIR__.'/bootstrap.php'; | |
| // ... lines 3 - 119 |
Refresh once more! Let's keep going.
Without including require_once __DIR__.'functions.php'; on top of lib/BattleManager.php file, how come the line 19 of lib/BattleManager.php file succeed to be executed ? As the didJediDestroyShipUsingTheForce() function was defined in functions.php ( before moving it to the BattleManager class ), wasn't it supposed to be needed to add require_once __DIR__.'functions.php'; on top of lib/BattleManager.php file ?