Principle: 依賴反轉原則
情境:目前電力系統採用火力發電
1 2 3 4 5 6 7 8 9 10 11 12
| <?php
namespace App\SOLID\DIP\PowerSystems;
class ThermalPower { public function generatePower() { return '電力'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
namespace App\SOLID\DIP\PowerSystems;
use App\SOLID\DIP\PowerSystems\ThermalPower;
class Program { public function getPower() { $thermalPower = new ThermalPower(); return $thermalPower->generatePower(); } }
|
隨著科技發展,現在我們想要改成用風力發電來取代火力發電,
卻發現原本的程式,強耦合在ThermalPower。
(依賴了具體的類別)
我們決定定義一個抽象的介面,
讓程式依賴在介面,並由各個發電方式實作介面。
改變彼此的依賴關係。
需求一:定義抽象介面,改變電力系統與火力發電的依賴關係
1 2 3 4 5 6 7 8 9
| <?php
namespace App\SOLID\DIP\PowerSystems\Contracts;
interface PowerGeneratable { public function generatePower(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\SOLID\DIP\PowerSystems;
use App\SOLID\DIP\PowerSystems\Contracts\PowerGeneratable;
class ThermalPower implements PowerGeneratable { public function generatePower() { return '電力'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\SOLID\DIP\PowerSystems;
use App\SOLID\DIP\PowerSystems\Contracts\PowerGeneratable;
class Program { public function getPower(PowerGeneratable $powerGeneration) { return $powerGeneration->generatePower(); } }
|
(註:現在要用什麼樣的發電方式,會交由客戶端決定)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php
namespace Tests\Feature\SOLID\DIP\PowerSystems;
use PHPUnit\Framework\TestCase; use App\SOLID\DIP\PowerSystems\Program; use App\SOLID\DIP\PowerSystems\ThermalPower;
class ProgramTest extends TestCase {
protected $sut;
protected function setUp(): void { $this->sut = new Program(); }
public function testGetPowerByThermalPower() { $expected = '電力'; $powerGeneration = new ThermalPower(); $actual = $this->sut->getPower($powerGeneration); $this->assertEquals($expected, $actual); } }
|
需求二:新增風力發電
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\SOLID\DIP\PowerSystems;
use App\SOLID\DIP\PowerSystems\Contracts\PowerGeneratable;
class WindPower implements PowerGeneratable { public function generatePower() { return '電力'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <?php
namespace Tests\Feature\SOLID\DIP\PowerSystems;
use PHPUnit\Framework\TestCase; use App\SOLID\DIP\PowerSystems\Program; use App\SOLID\DIP\PowerSystems\ThermalPower; use App\SOLID\DIP\PowerSystems\WindPower;
class ProgramTest extends TestCase {
protected $sut;
protected function setUp(): void { $this->sut = new Program(); }
public function testGetPowerByThermalPower() { $expected = '電力'; $powerGeneration = new ThermalPower(); $actual = $this->sut->getPower($powerGeneration); $this->assertEquals($expected, $actual); }
public function testGetPowerByWindPower() { $expected = '電力'; $powerGeneration = new WindPower(); $actual = $this->sut->getPower($powerGeneration); $this->assertEquals($expected, $actual); } }
|
最後附上類別圖比較:
- 依賴抽象的發電介面,並由各個發現方式實作介面
(可以觀察火力發電與風力發電的依賴方向,是不是反轉了呢)
ʕ •ᴥ•ʔ:透過遵守依賴反轉原則,我們也讓程式符合開放封閉原則。