Help us understand the problem. What is going on with this article?

第4章:But I remember オブジェクト指向

More than 5 years have passed since last update.

今回はオブジェクト指向を試してみるよ!

Scalaはオブジェクト指向もできるんだ!
ソースでの話がメインだよ。
だからオブジェクト指向プログラミングだ。

Javaだと冗長だけど、Scalaだとコンストラクタ・フィールドの
組み合わせで凄いシンプルになるんだ。

JavaBeans、いわゆる情報格納役で見てみよう。

Javaのソースコード

User.java
public class User {

    private final long id;

    private final String firstname;

    private final String lastname;

    public User(long id, String firstname, String lastname) {
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public long getId() {
        return id;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public String getFullname() {
        return this.firstname + " " + this.lastname;
    }
}

Javaプログラマーから見ると、普通のソースだと思う。
説明は省くよ!これをScalaにしてみよう。

Scalaのソースコード

User.scala
class User(val id: Long, val firstname: String, val lastname: String) {
  def getFullname() = this.firstname + " " +  this.lastname
}

なんということでしょう!
Javaだとダラダラ長かったソースが、わずか3行になってしまった。

クラスの書き方

  • クラス名は、classの後に書くんだ!
  • 引数は、クラス名の次に書くんだ!
  • メソッドは、{...}の中にdefで書くんだ!。

あれ?コンストラクタ宣言は?フィールド宣言は?

基本コンストラクタ

Scalaではクラス全体が基本コンストラクタというモノになる。
つまりコンストラクタはもう宣言してあるんだ。

フィールド宣言

基本コンストラクタの引数に、val(またはvar)を付ければ
そのままフィールドになる。

だからJavaでは長かったUserクラスが、Scalaでは3行で実現できたんだ。

フィールドへのアクセス

インスタンス.フィールドで可能だ!

val user = new User(1, "源次", "富樫")
user.firstname

直接フィールドにアクセスするのって、カプセル化の観点からいけないのでは?って。
確かにそうなんです。。。
今回はフィールドをvalにしているということで、許して下さい。

もちろん、フィールドに直接アクセスできないようにすることも可能だよ。

User1.scala
class User(private val id: Long, private val firstname: String, private val lastname: String) {
  def getFullname() = this.firstname + " " +  this.lastname
}

val user = new User(1, "源次", "富樫")
println(user.id)

引数の型の前に、privateを宣言した。

これを実行すると、

$ scala User1.scala
User1.scala:6: error: value id in class User cannot be accessed in this.User
println(user.id)
             ^
one error found

となり。外からはidフィールドにアクセスできないというエラーが出るよ。

これでgetterを用意すれば、フィールドに直接アクセスしないで
フィールドの値を取得できるね!

次にこのソースを少し変えてみよう!

改変したScalaのソース

User2.scala
class User(val id: Long, val firstname: String, val lastname: String, val fullname:Fullname = new Fullname) {
  def getFullname() = this.fullname.get(firstname, lastname)
}

class Fullname() {
  def get(firstname: String, lastname: String) = firstname + " " + lastname
}

class FullnameInJapan() extends Fullname {
  override def get(firstname: String, lastname: String) = lastname + " " + firstname
}

val user1 = new User(1, "源次", "富樫", new FullnameInJapan)
println(user1.getFullname())

val user2 = new User(2, "鯛雄", "松尾")
println(user2.getFullname())

今度は実行できるようにしてあるので、実行してみよう!

$ scala User2.scala
富樫 源次
鯛雄 松尾

出力結果だけど、user1user2firstnamelastnameの順番が違っているよね。

コンストラクタのデフォルト値

Userクラスのコンストラクタを先程とは少し変えているよ。わかるかな?

class User(val id: Long, val firstname: String, val lastname: String, val fullname:Fullname = new Fullname) {
  def getFullname() = this.fullname.get(firstname, lastname)
}

fullnameという引数を増やしているよ。型はFullnameだ。

そして= new Fullnameってあるよね?これがコンストラクタのデフォルト値だ。
このデフォルト値は、fullnameが指定されない場合に使用する。

val user2 = new User(2, "鯛雄", "松尾")

これがデフォルト値を使う場合だね。

ところでこのfullnameは何に使われるかと言うと、
メソッドgetFullnameの処理として呼び出されるのだ。

オブジェクト指向的に言うと、フルネームを作成するための処理を委譲しているのだ。
これでちょっとオブジェクト指向ぽくなったんじゃない?

オブジェクト指向プログラミングでは使われる頻度が多い、
Strategyパターンぽくしてみたよ。

クラスの拡張

クラスFullnameは次のようになっている。

class Fullname() {
  def get(firstname: String, lastname: String) = firstname + " " + lastname
}

そして、クラスFullname拡張してクラスFullnameInJapanを定義している。

class FullnameInJapan() extends Fullname {
  override def get(firstname: String, lastname: String) = lastname + " " + firstname
}

extendsで拡張し、overridでメソッドをオーバーライドする。
Javaとそんなに変わらないんだ。

クラスFullnameInJapanを使う場合は、以下のようになる。

val user1 = new User(1, "源次", "富樫", new FullnameInJapan)

これで、fullnameのデフォルト値を使わなくなる。

まとめ

今回はオブジェクト指向の中で、コンストラクタとフィールドに注力してみた。

Scalaでは冗長な部分を排除でき、単純に記述量が減り見通しが良くなることを
体で感じてくれたかな?

今回で、第一部を完了して、次章からScalaの世界で泳ぎ始めるよ!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away