がばがばscala独学 - オブジェクト

# はじめに

下記のテキストを通して、基本的な書き方を学びつつ、個人的に気になったことを検証していくメモ代わりです。
https://dwango.github.io/scala_text/basic.html
本当にありがとう、dwango様・・・

# オブジェクト

* ざっくりまとめ
    * クラスはstaticフィールド/メソッドが作成できない
    * オブジェクトによってstaticフィールド/メソッドを作成する

## オブジェクトの概要

* 全ての値がオブジェクト
    * 全てのメソッドは何らかのオブジェクトに所属
    * クラスに属するstaticフィールドやstaticメソッドといったものを作成することができない
* objectキーワードによって、同じ名前のシングルトンオブジェクトをグローバルな名前空間に1つ定義可能
    * [シングルトン](http://www.nulab.co.jp/designPatterns/designPatterns2/designPatterns2-1.html)より引用
        * オブジェクトを生成するnewは非常に負荷のかかる処理のため下記の手続きを実施
            1. シングルトンにしたいクラスをstaticなクラスフィールドとして用意
            1. コンストラクタをprivateに指定して、シングルトンクラス以外からコンストラクタの呼出し（newが使えなくなる）ができないようにする
            1. （外部よりnewが使えないため）取得するメソッドを用意
        * 毎回newするパターン(java)
            * ファクトリクラス
            
            ```java
            class Factory {
                public AbscructProduct create() {
                    return new Product;
                }
            }
            ```
            * ファクトリの使用

            ```java
            Factory factory = new Factory;
            AbscructProduct product = factory.create();
            product.do();
            ```
        * 上記をシングルトンにする(java)
            * ファクトリクラス
            
            ```java
            class Factory {
                private static Fatory instance = null;
                public static Factory getInstance() {
                    if (instance == null) {
                        instance = new Factory
                    }
                }
                public AbscructProduct create() {
                    return new Product;
                }
            }
            ```
            * ファクトリの使用
            
            ```java
            Factory factory = Factory.getInstance();
            AbscructProduct product = factory.create();
            product.do();
            ```
* object構文の主な用途
    * ユーティリティメソッドやグローバルな状態の置き場所（Javaで言うstaticメソッドやフィールド）
    * オブジェクトのファクトリメソッド
    * Singletonパターン
        * Singletonパターンを実現するために使われることはほとんどないとのこと

## object構文
* 一般型

    ```scala
    object オブジェクト名 extends クラス名 with トレイト名1 with トレイト名2 ... {
      本体
    }
    ```
    * Scalaでは標準でPredefというobjectが定義・インポートされていた
* 使用方法
    * ファクトリパターンでの使用方法

    ```scala
    scala> :paste
    // Entering paste mode (ctrl-D to finish)

    class Point(val x:Int, val y:Int)
    object Point {
        def apply(x: Int, y: Int): Point = new Point(x, y)
    }

    // Exiting paste mode, now interpreting.

    defined class Point
    defined module Point
    ```
    > Point(x)のような記述があった場合で、Point objectにapplyという名前のメソッドが定義されていた場合、Point.apply(x)と解釈されます。


* new Point()で直接Pointオブジェクトを生成するのに比べて、
    * クラス（Point）の実装詳細を内部に隠しておける（インタフェースのみを外部に公開する）
    * Pointではなく、そのサブクラスのインスタンスを返すことができる

## コンパニオンオブジェクト
クラス名と同じ名前のシングルトンオブジェクトはコンパニオンオブジェクトと呼ばれる

* NG/OKパターン

    ```scala
    scala> :paste
    // Entering paste mode (ctrl-D to finish)

    class Person(name: String, age: Int, private val weight: Int)

    object Hoge {
      def printWeight(): Unit = {
        val taro = new Person("Taro", 20, 70)
        println(taro.weight)
      }
    }

    // Exiting paste mode, now interpreting.

    <console>:12: error: value weight in class Person cannot be accessed in Person
               println(taro.weight)
                            ^

    scala> :paste
    // Entering paste mode (ctrl-D to finish)

    class Person(name: String, age: Int, private val weight: Int)

    object Person {
      def printWeight(): Unit = {
        val taro = new Person("Taro", 20, 70)
        println(taro.weight)
      }
    }

    // Exiting paste mode, now interpreting.

    defined class Person
    defined module Person
    ```

* objectとclassの定義による挙動
    * newしたらどうなるの？

        ```scala
        scala> :paste
        // Entering paste mode (ctrl-D to finish)

        class Point(val x: Int, val y: Int)

        val point = new Point(1, 2)
        println("point : " + point.x.toString() + ", " + point.y.toString())

        object Point {
            val x = 3
            val y = 4
            def printer(): Unit = {
                println("printer : " + x.toString() + ", " + y.toString())
            }
        }
        Point.printer()
        val repoint = new Point(1, 2)
        println("point : " + repoint.x.toString() + ", " + repoint.y.toString())
        Point.printer()

        // Exiting paste mode, now interpreting.

        point : 1, 2
        printer : 3, 4
        point : 1, 2
        printer : 3, 4
        defined class Point
        point: Point = Point@966dc35
        defined module Point
        repoint: Point = Point@3ae39f06
        ```
        * objectからの読み出しと、newは別途として扱われる

    * class定義から直接Objectは読み出しできる？
        
        ```scala
        scala> :paste
        // Entering paste mode (ctrl-D to finish)

        class Point(val x: Int, val y: Int)
        object Point {
            val x = 3
            val y = 4
            def printer(): Unit = {
                println("printer : " + x.toString() + ", " + y.toString())
            }
        }
        val point = new Point(1, 2)
        point.printer()

        // Exiting paste mode, now interpreting.

        <console>:20: error: value printer is not a member of Point
                      point.printer()
                            ^
        ```
        * newするとObjectはひっつかないためできない