Upgrade to Pro — share decks privately, control downloads, hide ads and more …

インターフェース再入門 / Think Interface again

インターフェース再入門 / Think Interface again

PHPカンファレンス 関西2018で発表しました。
https://2018.kphpug.jp/session/sugiura_sota

Sota Sugiura

July 14, 2018
Tweet

More Decks by Sota Sugiura

Other Decks in Technology

Transcript

  1. <?php class User { public function getName() { $rp =

    new Repository(); $name = $rp->getByName(); return $name; } } 3FQPTJUPSZ 6TFS HFU#Z/BNF
  2. <?php class User { public function getName() { $rp =

    new Repository(); $name = $rp->getByName(); return $name; } } 3FQPTJUPSZ 6TFS HFU#Z/BNF 中のロジックは 知らなくていい
  3. <?php class Database { public function getByName(string $name) { //

    Get data from database } } class User { /** @var Database */ protected $db; public function __construct(Database $db) { $this->db = $db; } public function getByName(string $name) { return $this->db->getByName($name); } } %BUBCBTF 6TFS HFU#Z/BNF
  4. <?php class Database { public function getByName(string $name) { //

    Get data from database } } class User { /** @var Database */ protected $db; public function __construct(Database $db) { $this->db = $db; } public function getByName(string $name) { return $this->db->getByName($name); } } • Userクラスが欲しい のはデータ • データの取得元はど こでもいい • にも関わらずコード ではDatabaseクラス に依存している
  5. <?php class Database { public function getByName(string $name) { //

    Get data from database } } class User { /** @var Database */ protected $db; public function __construct(Database $db) { $this->db = $db; } public function getByName(string $name) { return $this->db->getByName($name); } } • Userクラスが欲しい のはデータ • データの取得元はど こでもいい • にも関わらずコード ではDatabaseクラス に依存している 6TFSΫϥε͕ຊ౰ʹඞཁͳͷ͸ ʮHFU#Z/BNFΛ௨ͯ͡σʔλΛฦ͢ʯԿ͔
  6. <?php interface Repository { public function getByName(string $name); } class

    Database implements Repository { public function getByName(string $name) { // Get data from database } } • 「getByNameを通し てデータを得られる 何か」をInterfaceで 表現する • 各クラスはそれに従 い実装する
  7. <?php interface Repository { public function getByName(string $name); } class

    User { /** @var Repository */ protected $rp; public function __construct(Repository $rp) { $this->rp = $rp; } public function getByName(string $name) { return $this->rp->getByName($name); } } • Userクラスでは定め たInterfaceをtype hintする • 求めるInterfaceと 役割をコードで表現 できる
  8. <?php interface File { public function open(string $filename); public function

    read(int $count); public function close(); } Example - 最⼩のInterface
  9. <?php interface File { public function open(string $filename); public function

    read(int $count); public function close(); } Example - 最⼩のInterface open, read, close関数を駆使すれば 1⾏ずつ読み込むことができる
  10. <?php interface File { public function open(string $filename); public function

    read(int $count); public function readLine(int $lineNum); public function close(); } Example - 完全なInterface
  11. <?php interface File { public function open(string $filename); public function

    read(int $count); public function readLine(int $lineNum); public function close(); } Example - 完全なInterface readLine関数で⼀⾏ずつ読むのは簡単!
  12. <?php interface File { public function open(string $filename); public function

    read(int $count); public function readLine(int $lineNum); public function close(); } Example - 完全なInterface readLine関数で⼀⾏ずつ読むのは簡単! ҰํͰ࣮૷ͱςετͷ௥Ճɺ ͦΕͷอकίετ͕ൃੜ͢Δ
  13. <?php interface Image { public function setWidth(int $width); public function

    setHeight(int $height); public function setName(string $name); } Example - 単純なInterface
  14. <?php interface Image { public function setWidth(int $width); public function

    setHeight(int $height); public function setName(string $name); } Example - 単純なInterface 縦と横のサイズ、名前だけ変更できる
  15. <?php interface Image { public function setWidth(int $width); public function

    setHeight(int $height); public function setName(string $name); public function setBrightness(int $level); public function setPixel(int $pixel); public function setEffect(string $effect); public function setExtension(string $ext); } Example - 複雑なInterface
  16. <?php interface Image { public function setWidth(int $width); public function

    setHeight(int $height); public function setName(string $name); public function setBrightness(int $level); public function setPixel(int $pixel); public function setEffect(string $effect); public function setExtension(string $ext); } Example - 複雑なInterface 画像に対して細やかな調整が可能!
  17. <?php interface Image { public function setWidth(int $width); public function

    setHeight(int $height); public function setName(string $name); public function setBrightness(int $level); public function setPixel(int $pixel); public function setEffect(string $effect); public function setExtension(string $ext); } Example - 複雑なInterface 画像に対して細やかな調整が可能! ҰํͰΠϯλʔϑΣʔεΛ ཧղ͢Δͷ͕೉͍͠
  18. トレードオフ • 単純 • メソッド数が少なく、理解が容易 • 細やかな変化に対応できない • 複雑 •

    細やかな操作が呼び出し側で可能 • インターフェースの理理解が難しい
  19. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } 作ってみた
  20. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } 作ってみた ⼈を表す名前に
  21. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } 作ってみた 名前を情報として持つ
  22. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } 作ってみた 役割を取得できるように
  23. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } Person Interface
  24. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } Person Interface
  25. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function getRole(): string; } Person Interface おさらい:実現したいこと 「その⼈が特定の役割を持つか確かめる⼿段が欲しい」
  26. <?php class Manager { public function assign(Person $person) { if

    ($person->getRole() === 'admin') { // } } } 使い⼿の気持ちになる
  27. <?php class Manager { public function assign(Person $person) { if

    ($person->getRole() === 'admin') { // } } } 使い⼿の気持ちになる getRole()を駆使しないと 「その⼈が特定の役割を持つか確かめる⼿段が欲しい」 が実現できない
  28. <?php class Manager { public function assign(Person $person) { if

    ($person->getRole() === 'admin') { // } } } 使い⼿の気持ちになる 最⼩/完全という観点で⾒ると最⼩と⾔えそうだが そもそも現時点でgetRole()を求められていない
  29. <?php class Manager { public function assign(Person $person) { if

    ($person->isRole('admin')) { // } } } 改良版 1つメソッドを呼ぶだけで要件を実現できた 名前も今回求める役割を表現できてる
  30. <?php class Manager { public function assign(Person $person) { if

    ($person->isAdmin()) { // } } } 改良版 最⼩のインターフェースから完全へ
  31. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function isRole(string $role): bool; public function isAdmin(): bool; } Person Interface
  32. <?php interface Person { public function getName(): string; public function

    setName(string $name); public function isRole(string $role): bool; public function isAdmin(): bool; } Person Interface これは必要…? 今回の要件には含まれていない
  33. <?php interface Person { public function getName(): string; // public

    function setName(string $name); public function isRole(string $role): bool; public function isAdmin(): bool; } Person Interface
  34. <?php interface Person { public function getName(): string; public function

    isRole(string $role): bool; public function isAdmin(): bool; public function isSysAdmin(): bool; public function isGeneral(): bool; } Person Interface
  35. <?php interface Person { public function getName(): string; public function

    isRole(string $role): bool; public function isAdmin(): bool; public function isSysAdmin(): bool; public function isGeneral(): bool; } Person Interface 予測できる未来として「役割の種類が増える」ことが 考えられる
  36. <?php interface Person { public function getName(): string; public function

    isRole(string $role): bool; public function isAdmin(): bool; public function isSysAdmin(): bool; public function isGeneral(): bool; } Person Interface 仮に役割が増えるとすると、 Interfaceの完全さを保とうとすればするほど メソッドは増え、保守性は下がる