初めに
インターフェースと抽象クラスってできることほぼ同じで使い分けとかいまいちわかってないなということで理解を深めて正しく使い分けれるようにしたいと思いこの記事を書こうと思いました。
調べる前のイメージはインターフェースは依存性逆転のために使われるのはよく見るけど、抽象クラスってそもそもあんま使われてるイメージがないという感じです。
インターフェースと抽象クラスの比較
抽象クラス | インターフェース | |
---|---|---|
アクセス修飾子 | public,protected | publicのみ |
定数の定義 | インスタンス変数、ローカル変数、クラス変数など定義できる | クラス変数しか定義できない |
多重継承 | 不可 | 可能 |
メソッドの定義 | 具体的な処理もかける | メソッドの型しか定義できない |
上から順番にコードを書いて試してみます。
抽象クラスのアクセス修飾子
abstract class Hoge {
abstract public function fuga1();
abstract protected function fuga2();
abstract private function fuga3();
}
実行結果
Abstract function Hoge::fuga1() cannot be declared private
インターフェースのアクセス修飾子
interface Hoge {
public function fuga1();
protected function fuga2();
private function fuga3();
}
実行結果
Access type for interface method Hoge::fuga2() must be public
抽象クラスの変数の定義
abstract class Hoge {
// インスタンス変数
public string $fuga1 = "";
// クラス変数
const fuga = '';
}
インターフェースの変数の定義
interface Hoge {
const fuga = '';
public string $fuga1 = "";
}
実行結果
Interfaces may not include properties
抽象クラスの多重継承
class Hoge extends Hoge1, Hoge2 {
public function fuga1() {
}
public function fuga2() {
}
}
abstract class Hoge1 {
public function fuga1();
}
abstract class Hoge2 {
public function fuga2();
}
実行結果
syntax error, unexpected token ",", expecting "{"
他の言語はわからないですが、PHPでは多重継承できないみたいなエラーじゃなくてそもそも構文エラーになるんですね。
インターフェースの多重継承
class Hoge implements HogeInterface1, HogeInterface2 {
public function fuga1() {
}
public function fuga2() {
}
}
interface HogeInterface1 {
public function fuga1();
}
interface HogeInterface2 {
public function fuga2();
}
問題なく実行できました。
抽象クラスの具体的な処理
abstract class Hoge1 {
public function fuga1() {
echo "fuga1";
}
}
問題なく実行できました。
インターフェースの具体的な実装
interface HogeInterface1 {
public function fuga1() {
echo "fuga1";
}
}
実行結果
Interface function HogeInterface1::fuga1() cannot contain body
概念的な話
元々抽象クラスとインターフェースはどういう役割を持つために作られたのかを調べてみました。
抽象クラスはもの
を定義するために作られたそうです。
ものはものでももっと抽象的な例えば
- 犬、猫、人間をもっと抽象的にすると動物
- 車、バイクをもっと抽象的にすると乗り物
といったように大分類的な表現のものを定義して、そこから子クラスに継承するといった役割。
次にインターフェースは振る舞い
を定義するために作られたそうです。
ふるまいとは「〜できる」といったような例えば
- 歩くことができる
- 食べることができる
などがあてははまるかと思います。
抽象クラスと具象クラスはis-aの関係で例えば
犬は動物である。
車は乗り物である。
という関係性である必要があるそうです。
使い分けは?
極端に言えば、共通的に扱いたいグループが、もの(Object)で分類することができる場合、抽象クラスにし、それ以外の場合は、インターフェースにするとそれぞれのできた経緯に沿った実装ができるのかなと思います。
さいごに
インターフェースと抽象クラスについて書きましたが、正直抽象クラス使わずに基底クラス的なの作ってる実装がほとんどな印象なのであまり意識する必要はないのかもしれないですがなぜ抽象クラスを実装するのかという記事があったので参考までに貼っておきます。
参考