デザインパターンをkotlinで書いてみた　Singleton編

オブジェクト指向で大切になるInterfaceの考え方やオブジェクトの再利用性を学ぶために[「Java言語で学ぶデザインパターン入門」](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797327030/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80&qid=1559563427&s=gateway&sr=8-1)について学び、Javaとついでにkotlinで書いてみることにしました。
今回はSingletonについてまとめます。

※また、コメント欄にレビューをいただきました @sdkei さんありがとうございます。
レビューを元に修正しました内容を反映させましたので、その点も踏まえて書いていこうと思います。

##Singletonとは
singletonとは要素を一個しか持たない集合を指す言葉で、下記役割を果たすパターンとして定義されています。

+ 指定したクラスのインスタンスが絶対に一個しかないことを保証したい
+ インスタンスが一個しか存在しないことをプログラム上で表現したい



##Singletonクラス
このクラスではstaticフィールドとして定義された`singleton`メンバにSingletonクラスのインスタンスで初期化していますが、クラスのロード時に一度だけ初期化が行われます。
また、privateで外部からのアクセスを防ぐことでインスタンスが一個しか生成されないことを保証しているとの事。

kotlinの場合、staticという定義はなく、代わりに`companion object`を定義します。
>参考：[Kotlin で static なメンバーをどう書くべきなのか?](https://android.benigumo.com/20170810/kotlin-static-member/)

また、`companion object`を定義してデコンパイルするとCompanionオブジェクトを介したgetter/setterからアクセスすることになるのでconstか@JvmFieldを使用するとのこと。
しかし、constはプリミティブ型かString型のみなので非プリミティブ型は@JvmFieldを指定し、プリミティブ型を@JvmField指定すると2回初期値を代入するため使い分ける必要があるとのこと。
ただ、@JvmFieldはFieldに可視性を持たすために使用するため、今回のprivateでは使用できなかった。

>参考：
[【Kotlin】【Java】Kotlin Javaの比較メモ](https://qiita.com/farman0629/items/f959a4ff791f26b33fc3)
[Calling Kotlin from Java](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/java-to-kotlin-interop.html)

__追記：@sdkei さんレビューありがとうございます！__
レビューをいただき、上記のような実装でなくてもKotlinにはオブジェクト宣言を使用してより容易に実装できるようになっているとのことです。
⇒`Singleton2.kt`,`SingletonSample2.kt`

>参考：
[Kotlinでデザインパターン Singleton編](https://qiita.com/kaleidot725/items/611e00f7413c208809a3)
[オブジェクト式と宣言](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/object-declarations.html)

```java:Singleton.java
class Singleton {
	private static Singleton singleton = new Singleton();
	private Singleton() {
		System.out.println("インスタンスを生成しました。");
	}
	public static Singleton getInstance() {
		return singleton;
	}
}
```
```kotlin:Singleton.kt
class Singleton {
    init { println("インスタンスを生成しました。") }
    companion object {
       private val singleton = Singleton()
       fun getInstance() = this.singleton
    }
}
```
```kotlin:Singleton2.kt
object Singleton {
    init { println("インスタンスを生成しました。") }
}
```

##Mainクラス

```java:SingletonSample.java
public class SingletonSample {
	public static void main(String[] args) {
		System.out.println("Start.");
		Singleton s1 = Singleton.getInstance();
		Singleton s2 = Singleton.getInstance();
		if (s1 == s2) {
			System.out.println("s1とs2は同じインスタンスです。");
		} else {
			System.out.println("s1とs2は同じインスタンスではありません。");
		}
		System.out.println("End.");
	}
}
```
```kotlin:SingletonSample.kt
fun main(args: Array<String>) {
    println("Start.")
    val s1 = Singleton.getInstance()
    val s2 = Singleton.getInstance()
    if (s1 == s2) println("s1とs2は同じインスタンスです。")
    else println("s1とs2は同じインスタンスではありません。")
    println("End.")
}
```
```kotlin:SingletonSample2.kt
fun main(args: Array<String>) {
    println("Start.")
    val s1 = Singleton
    val s2 = Singleton
    if (s1 == s2) println("s1とs2は同じインスタンスです。")
    else println("s1とs2は同じインスタンスではありません。")
    println("End.")
}
```

```console:実行結果
Start.
インスタンスを生成しました。
s1とs2は同じインスタンスです。
End.
```

##クラス図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326131/32b4f263-cecf-f422-66aa-56bad57dcd7c.png)

##所感
+ staticなフィールドとして定義された`singleton`メンバにSingletonクラスのロード時に一度だけ初期化を行い、privateで外部からのアクセスを防ぐことでインスタンスが一個しか生成されないことを保証していることを学んだ。
+ また、上記保証により、シリアルナンバーなどの一意である必要がある実装の際にメリットになることを学んだ。

+ Kotlinについては下記の点を学ぶことができた

1. staticの代わりに`companion object {}`を定義する
2. companion内でプリミティブ型とString型は`const`, 非プリミティブ型は`@JvmField`を指定
3. privateの場合はそのまま使用
4. オブジェクト宣言により容易にSingletonパターンを使用できること

##参考
下記を参考にさせて頂き、大変読みやすく、理解しやすかったです。

[Kotlin で static なメンバーをどう書くべきなのか?](https://android.benigumo.com/20170810/kotlin-static-member/)
[【Kotlin】【Java】Kotlin Javaの比較メモ](https://qiita.com/farman0629/items/f959a4ff791f26b33fc3)
[Calling Kotlin from Java](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/java-to-kotlin-interop.html)
[Kotlinでデザインパターン Singleton編](https://qiita.com/kaleidot725/items/611e00f7413c208809a3)
[オブジェクト式と宣言](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/object-declarations.html)