こんにちは!なるーらぼです。いよいよGroovyもオブジェクト指向へと足を踏み入れました。といっても、もうずっとオブジェクト指向の中にいるのですが・・・
オブジェクト指向とは
ややこしい話はここでは割愛したいと思います。Javaと同じ書き方ができる、ということであればJavaを学んだことがある方にはさほど難しいことはありません。むしろ、いままで避けてきたなーという方に向けてお話ししたいと思います。
めちゃくちゃ掻い摘んで言いますと、以下の特徴があります。
- 「○○というのはこういうものだ」としたモデルをつくる
- 「直接さわってほしくないもの」は外から隠す
- モデルを実体化して指令をすることで動かす
例えば、ロボットを考えてみます。わたしの考えたロボットは2次元で、こんなやつです。
- 名前をつけることができる
- 表面に色がついている
- 簡単な言葉を話す
- 移動することができる
これをGroovyで記述するとこんな感じでしょうか。
class Robot{
String name
String bodyColorString speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
def robot = new Robot(name: "nalulabo", bodyColor: "green")
assert robot.name == "nalulabo"
assert robot.bodyColor == "green"
println "ロボットは言った:${robot.speech()}"
robot.walk()
いかがでしょうか?「こんなやつです」とお話しした内容になっていると思います。
その「こんなやつ」を決めるところですが、「class」というキーワードから始まって、クラス名のあとに続く波括弧の中で記述していきます。ここでは「こんなやつ」を決めたところだけを書いてあります。名前、ボディの色、それからしゃべる内容、歩く…
こうしたものは外側から確認したり命令したりすることができます。しかしそのためには絵に描いた餅ではだめで、現実に登場してもらう必要があります。
それをしているのが以下の部分です。
def robot = new Robot(name: "nalulabo", bodyColor: "green")
ここで変数robotにはクラス「Robot」に初期設定を与えて実体化させています。名前は「nalulabo」で、ボディの色は「green」です。この設定で作成されたRobotクラスの実体が変数robotへ指定されたわけです。
こうして実体化したロボットは設計図から飛び出して目の前に実在します。そこでロボットへ確認できるものは名前だったり表面の色だったりするわけです。さらに、実体化しているので指令を出すことができて、「話をして」と言ってみたり「歩いて」と言ってみたりできたのです。
コンストラクタ
さて、さきほどのロボットを実体化するときに行った「new」を使った命令ですが、これはRobotクラスが実体化するときの初期設定を行う命令が呼び出されています。それをコンストラクタと呼びます。
ん?そんなもの書いてないじゃないかって?そうです。Groovyでは記述しなければ自動的にコンストラクタは作成してもらうことができます。しかもコンストラクタの呼び出しのときに名前付きでパラメータを設定することができるのです。こうしたコンストラクタのことを「名前付きコンストラクタ」と呼びます。そのまんまですね。
もしも名前なんてどうでもいいから順番に指定したいよ!という方には明示的にコンストラクタを記述してあげてください。コンストラクタは特殊なメソッドで、オブジェクトが出来上がるときの1度だけ呼び出されます。
返す値を設定することはできませんが、何か初期設定時にしたいことがあればここで設定できるようにすると便利ですね。では明示的なコンストラクタで書き換えてみましょう。
class Robot{
String name
String bodyColorRobot(name, bodyColor){
this.name = name
this.bodyColor = bodyColor
}
String speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
def robot = new Robot("nalulabo", "green")
assert robot.name == "nalulabo"
assert robot.bodyColor == "green"
println "ロボットは言った:${robot.speech()}"
robot.walk()
こうすると、名前付きコンストラクタを使用することはできなくなります。どちらがいいかは用途に応じて選んでみましょう。
プロパティ
ところで、先ほどのロボットですが後から好きなだけ名前を変えることができます。
def robot = new Robot(name: "nalulabo", bodyColor: "green")
println "ロボットの名前:${robot.name}です"
robot.name = "イエスマン"println "ロボットの名前:${robot.name}です"
これを実行すると・・・
ロボットの名前:nalulaboです
ロボットの名前:イエスマンです
おお、変わってしまったのね・・・
こうした外側から見ることができたり、値をセットすることができる内容のことをプロパティと言います。プロパティは読み取り専用にしたり、書き込みができるようにしたりすることができます。Javaではこうしたプロパティを実現するとき、nameというプロパティのために「getName」そして「setName」というメソッドを記述する必要がありました。
もちろんそちらの方法も利用することができますし、明示しなければ自動的にGroovyが生成してくれます。もしも値をセットしたり取り出すときに何らかのカスタマイズが必要であれば、明示的に記述することでカスタマイズすることができます。
class Robot{
String name
String bodyColorString getName() { "ワタシハ${this.name}デス" }
String speech(){
"コンニチハ"
}
void walk(){
println "ウィーーーン"
}
}
def robot = new Robot(name: "nalulabo", bodyColor: "green")
println "ロボットの名前:${robot.name}"
内部クラス
Javaと同様にGroovyもクラスの中にクラスを入れ子にすることができます。この入れ子になったクラスのことを内部クラスと言います。この内部クラスは外側から直接実体化されたくない、だけど特定のクラスからは実体化したいという場合に便利です。
class Robot{
final String name
String bodyColorRobot(name, bodyColor) {
this.name = name
this.bodyColor = bodyColor
}
String speech(){
new SpeechMachine(words: "コンニチハ").sayWords()
}
void walk(){
println "ウィーーーン"
}
class SpeechMachine{
private String words
String sayWords(){
"${this.words}"
}
}
}
def robot = new Robot("nalulabo", "green")
println robot.speech()
上記の例ではRobotクラスの中にSpeechMachineという内部クラスがあります。これを実体化するときに、話す言葉を与えています。そして話す(speechメソッドを呼び出した)ときに内部クラスSpeechMachineの「sayWords」メソッドが呼び出されることで「コンニチハ」と表示させています。とはいえ、こんな内容であればわざわざ使わなくてもよいのかもしれませんが…
抽象クラス
さて、さらによくわからないものが登場してきました。次は抽象クラスです。抽象クラスは普通のクラスとそれほど違いがありませんが、大きな違いとして実体化することができないということがあります。あら、ものすごい違いかもしれませんね!ということは、これ単体では動作しないということです。
抽象クラスを定義するには「class」キーワードの前にさらに「abstract」をつけます。メソッドに実装を書いておくことができますが、メソッドにも「abstract」をつけると抽象メソッドとなるので実装を書いてはいけません。
abstract class Machine {
String name
abstract def speech()String ping() {
println "pong"
}
}
この考え方は次回の継承のところで活用していくことになります。
最後に
いよいよ登場したクラスですが、rubyやpythonにもありますのでそれほど目新しいものではないと思います。
次回は継承についてみていきたいと思います。
0コメント