この記事は
個人的に、interfaceが何なのかは分かっていて、書いたことはそんなに無いけども、使ったことはある。
誰かが書いたのを呼び出して色々やっているけども、書いた人がどういう意図でinterfaceを定義したのかいまいちよく分かってない。
独り言はここまでにして、要はinterfaceの意義が分からないので、それを解消する記事にしたいと思います。
なので、対象は
- interfaceの概念が分からない人
- interfaceの概念は分かるけど、何のためにあるのか分からない人
あ、ここで出てくる具体例は全て、"Kotlin"のインターフェースです。
言語とそのバージョンによって、微妙に仕様が異なる可能性があるので最初に伝えておきます。
ただ、interfaceの意義は掴めると思います。
interfaceとは
一言で表すと「約束」。
抽象メンバを定義することが出来ます。
そして、クラスに実装する事で定義した抽象メンバを強制的にオーバーライドさせられます。
interface Life {
var hitPoint: Int
fun walk()
fun run()
fun eat()
fun sleep() {
// 中身の実装はあってもなくても良い
}
}
class Human: Life {
override var hitPoint: Int = 100
override fun walk () {
print("I walk")
}
override fun run() {
print("I run")
}
override fun eat() {
print("I eat rice")
}
override fun sleep() {
print("I sleep")
}
}
なぜinterfaceがいるのか?
さて、本題。
ただ、調べているとよく"abstract class vs interface"と出てきます。
そのため、一応、似た概念である「抽象クラス」も触れていきます。
その為に、こんな流れで説明していきます。
- 抽象クラスの説明
- インターフェースと同じところ
- インターフェースとの違い
- インターフェースはどんな問題を解決してくれるのか?
普通のクラスとインターフェースの違い
- 抽象メンバを持つことが出来る
- インターフェースは、コンストラクタを持つことが出来ない
抽象クラスについて
一言で表すと「始祖」。
直接インスタンス化して実態を生成することができないこと、そして、多重継承出来ないので始祖感ありません?
抽象メソッドや抽象プロパティを定義することができると同時に、具体的なメソッドやプロパティを追加することもできます。
直接インスタンス化ができないのと抽象メンバを持てるというだけで、普通のクラスと大体同じですね。
あとあと、継承したら全てのメンバをオーバーライドしないといけないという点も抽象クラスの特徴です。(神の力ですね)
abstract class God(val people: Double) {
// コンストラクタ引数も持つことができる
}
抽象メソッドとは?
一言で表すと「具無し」メソッドです。
引数と戻り値の型だけを指定して、具体的な処理は書かない。
文字通り、抽象的なメソッドです。
abstract fun hoge(str: String): Int
抽象クラスとインターフェースの違い
インターフェースも抽象クラスも抽具メンバも定義できる点では、同じなのですがインターフェースは
-
多重継承が可能
-
コンストラクタ引数を持つことができない
-
バッキングフィールドを持つことができない
private var _name: String = " " // _nameがバッキングフィールド
var name: String
get() {
return _name
}
set(value) {
_name = value
}
抽象クラスとインターフェースの同じところ
- 抽象メンバを持てる
- 抽象メンバを全てオーバーライドしないといけない
- インスタンス化できない
改めてインターフェースの意義とは?
文法的には、分かったとは思うので、
- interfaceの概念が分からない人
に向けてはOKです。
ただ、ここまで抽象クラスとインターフェースの類似点と相違点を挙げましたが、正直分からないのが正直な所。
何かの意義を感じ取るには、やはり問題となる具体例が必要だと思います。
それを引き合いに出しながら
- interfaceの概念は分かるけど、何のためにあるのか分からない人
に向けてとどめを刺したいと思います。
インターフェースが解決してくれる問題
下記の具体例がとても分かりやすかったので、まずはこちらをご覧ください。
インターフェースの文法を一言で表すと「約束」。
ただし、インターフェースが解決してくれる問題を考えると、この要約だけでは微妙です。
役割としては、複数あって
- 約束
- 仲介
- 分岐
まずは、文法から理解できることで、
interfaceで定義した抽象メンバの機能をクラスが持つことを「約束」できます。
以下二つは、インターフェースの役割を考察したもの。
まず、疎結合が実現できているのは、実装クラスと呼び出し元のクラスの間に立つ「仲介」を担っているから。
そして、上記の例にあるように、Qiitaサーバーへのリクエストという共通機能を提供する中で、クラスへの安全なアクセスを実現するために、ラム専とロム専で「分岐」していました。
まとめ
割と奥が深いインターフェース・・
大事な部分をあうとそーしんぐしてしましましたが、何とか一つの理解の形になったと思います。
間違っている箇所があれば、優しく教えてください!
参考