2014年09月23日
Posted by 屋台ブルー at
2014年09月23日00:00 Comment(0)
Swiftで遊ぼう! - 74 オブジェクト指向1 ポリモーフィズム
オブジェクト指向の重要な3項目は、「クラス」、「ポリモーフィズム」、そして「継承」だ。その中で、ポリモーフィズムは理解しがたくちょっと考えてみる。
「ポリモーフィズム」は、多形性、多様性、多相性と日本語訳されているけど、色々とプログラムの形態を変えていくというイメージがある。言葉のイメージからみると、「継承」と何が違うのか相違点が見えない。
「ポリモーフィズム」は、どちらかと言えば、クラスにある種のメソッドがあれば、同じメソッドをコールしても、「インスタンス毎に返す結果が異なるという多様性」と考えていいのでしょうか? ちょっと言葉で説明すると、何を言っているのか分からなくなるのでコードでみてみよう。
class Person {
var name: String
init(name: String) {
self.name = name
}
func callName() -> String {
return name
}
}
まずベースクラスの「Person」を作ってみる。これにはString型の「name」プロパティとString型の名前を返すだけのcallNameという関数(メソッド)だけを持っている。けど、サブクラスでこれを拡張していくわけで、「継承」と「ポリモーフィズム」は、同じような手順であるが利用法が異なると考えていいのだろうか? ベースクラスの関数がインターフェイスの役割を果たすということにすれポリモーフィズムということかな?
class Man: Person {
override init(name: String) {
super.init(name: name)
}
override func callName() -> String {
return "My name is \(name), and I'm a guy!"
}
}
class Woman: Person {
override init(name: String) {
super.init(name: name)
}
override func callName() -> String {
return "My name is \(name), and I'm a lady!"
}
}
そして、上に書いている「Person」クラスを継承した2つのサブクラス「Man」と「Woman」クラスを作り、ベースメソッドのオーバライドをすることで、別々の機能を割り当てた。
var yuji = Man(name: "Yuji Tai")
var miyuki = Woman(name: "Miyuki Tai")
そして、これでサブクラス「Man」と「Woman」からそれぞれ「yuji」と「miyuki」というインスタンスを作る。
class Calling {
func callName(name: Person) -> String {
return name.callName()
}
}
ポリモーフィズムのミソは、上に書いたクラスだろう(共通メインルーチンにあたるベースクラス「Person」を呼ぶクラス)。しかし、何か納得できないのは、このクラスのメソッド名だけど、「Person」クラスと同じ名前にしているけど、関数名を変更しても普通に問題なく動く。しかし、ポリモーフィズム的に名前を同じにした方がいいんでしょうね。この関数で呼び出しているのが、ベースクラスで定義しているメソッドなので、引数にサブクラスのインスタンスを入れることで、振る舞いを変えることができる。これが、ポリモーフィズムということかな? プロトコールを使った方がすっきりすると思ったけど、どうしてもProtocolを利用できない。まだまだ勉強不足です(T_T)
var uniCall = Calling()
uniCall.callName(yuji)
uniCall.callName(miyuki)
println(uniCall.callName(yuji))
// My name is Yuji Tai, and I'm a guy!
println(uniCall.callName(miyuki))
// My name is Miyuki Tai, and I'm a lady!
このように同じメソッドcallNameを呼んでも、異なる結果になりました。
「ポリモーフィズム」は、多形性、多様性、多相性と日本語訳されているけど、色々とプログラムの形態を変えていくというイメージがある。言葉のイメージからみると、「継承」と何が違うのか相違点が見えない。
「ポリモーフィズム」は、どちらかと言えば、クラスにある種のメソッドがあれば、同じメソッドをコールしても、「インスタンス毎に返す結果が異なるという多様性」と考えていいのでしょうか? ちょっと言葉で説明すると、何を言っているのか分からなくなるのでコードでみてみよう。
class Person {
var name: String
init(name: String) {
self.name = name
}
func callName() -> String {
return name
}
}
まずベースクラスの「Person」を作ってみる。これにはString型の「name」プロパティとString型の名前を返すだけのcallNameという関数(メソッド)だけを持っている。けど、サブクラスでこれを拡張していくわけで、「継承」と「ポリモーフィズム」は、同じような手順であるが利用法が異なると考えていいのだろうか? ベースクラスの関数がインターフェイスの役割を果たすということにすれポリモーフィズムということかな?
class Man: Person {
override init(name: String) {
super.init(name: name)
}
override func callName() -> String {
return "My name is \(name), and I'm a guy!"
}
}
class Woman: Person {
override init(name: String) {
super.init(name: name)
}
override func callName() -> String {
return "My name is \(name), and I'm a lady!"
}
}
そして、上に書いている「Person」クラスを継承した2つのサブクラス「Man」と「Woman」クラスを作り、ベースメソッドのオーバライドをすることで、別々の機能を割り当てた。
var yuji = Man(name: "Yuji Tai")
var miyuki = Woman(name: "Miyuki Tai")
そして、これでサブクラス「Man」と「Woman」からそれぞれ「yuji」と「miyuki」というインスタンスを作る。
class Calling {
func callName(name: Person) -> String {
return name.callName()
}
}
ポリモーフィズムのミソは、上に書いたクラスだろう(共通メインルーチンにあたるベースクラス「Person」を呼ぶクラス)。しかし、何か納得できないのは、このクラスのメソッド名だけど、「Person」クラスと同じ名前にしているけど、関数名を変更しても普通に問題なく動く。しかし、ポリモーフィズム的に名前を同じにした方がいいんでしょうね。この関数で呼び出しているのが、ベースクラスで定義しているメソッドなので、引数にサブクラスのインスタンスを入れることで、振る舞いを変えることができる。これが、ポリモーフィズムということかな? プロトコールを使った方がすっきりすると思ったけど、どうしてもProtocolを利用できない。まだまだ勉強不足です(T_T)
var uniCall = Calling()
uniCall.callName(yuji)
uniCall.callName(miyuki)
println(uniCall.callName(yuji))
// My name is Yuji Tai, and I'm a guy!
println(uniCall.callName(miyuki))
// My name is Miyuki Tai, and I'm a lady!
このように同じメソッドcallNameを呼んでも、異なる結果になりました。