R5 (ReferenceClass) で Singleton
こんな感じでどうでしょうか?
Singleton <- setRefClass(
"Singleton"
)
(function(new) {
new # to avoid lazy evaluation
Singleton$getInstance <- function() {
instance <- new()
Singleton$.instance <- instance
Singleton$getInstance <- function() {
return(Singleton$.instance)
}
return(instance)
}
})(Singleton$new)
Singleton$new <- NULL
ポイントは次のとおりかと思います。
- Singleton$new を closure に退避した上で Singleton$new に NULL を代入して使えなくする
- 最初に Singleton$getInstance を実行した時に初めてインスタンスを作成する
- インスタンスを作成したら Singleton$getInstance を書き換える
Singleton$getInstance を書き換えずに if で分岐させてもいいんですが、毎回条件式が評価されるのもなんか嫌なので・・・。”return(Singleton$.instance || (Singleton$.instance <- instance))” みたいに書けるといいんですけどね。
使ってみる
次のようにちょっとだけ手を加えたやつを使います。
Singleton <- setRefClass(
"Singleton",
fields = list(
variable = "numeric"
),
methods = list(
initialize = function() {
cat("create instance\n")
variable <<- 1
}
)
)
Singleton$accessors(names(Singleton$fields()))
(function(new) {
new # to avoid lazy evaluation
Singleton$getInstance <- function() {
instance <- new()
Singleton$.instance <- instance
Singleton$getInstance <- function() {
return(Singleton$.instance)
}
return(instance)
}
})(Singleton$new)
Singleton$new <- NULL
以下、動作確認です。
> a <- Singleton$getInstance()
create instance
> b <- Singleton$getInstance()
> a$getVariable()
[1] 1
> b$getVariable()
[1] 1
> a$setVariable(100)
> a$getVariable()
[1] 100
> b$getVariable()
[1] 100
> as.environment(a)
<environment: 0x106e1fed0>
> as.environment(b)
<environment: 0x106e1fed0>
> Singleton$new() # 新しくインスタンスを作ることはできない
Error: attempt to apply non-function
おもしろいですね!!
もっと良い方法があったら教えてください。