#State
目次
よくXXXStatus
のような状態を管理するプロパティを持たせ、switch(XXXStatus){ // caseにより色々な処理を行う }
ような実装をすることがあると思います。
状態が増えるとswitch文が長々と続くことになり読む側も大変になっていくのを、状態1つ1つをオブジェクトにすることによりスマートにしようというのが本パターンの主旨だと考えています。
##目的
オブジェクトの内部状態が変化したときに、オブジェクトが振る舞いを変えるようにする。クラス内では、振る舞いの変化を記述せず、状態を表すオブジェクトを導入することでこれを実現する。
##構成要素
・Context 色々な状態があるクラス
・State 状態の抽象クラス
・ConcreteState 状態の具象クラス
##実装
自動販売機を実装することにします。
実装する自動販売機の状態としては以下の2つの状態と2つの操作があることと、商品の価格は一律100円とします。
状態
・商品の価格未満の金額が入金されている。
・商品の価格以上の金額が入金されている。
操作
・入金する。
・商品のボタンを押す。
###State 状態の抽象クラス
package state
interface State {
fun coin(v: VendingMachine)
fun push(v: VendingMachine)
}
###ConcreteState 状態の具象クラス
商品の価格未満の金額が入金されている状態を表すクラス
package state
class LackState: State {
override fun coin(v: VendingMachine) {
v.insertMoney(50)
}
override fun push(v: VendingMachine) {
v.errorMessage()
}
}
商品の価格以上の金額が入金されているクラス
package state
class SufficientState: State {
override fun coin(v: VendingMachine) {
v.warningMessage()
}
override fun push(v: VendingMachine) {
v.buy()
}
}
###Context 色々な状態があるクラス
抽象クラス
package state
interface Context {
fun coin()
fun push()
}
自動販売機具象クラス
package state
class VendingMachine: Context {
companion object {
private val lack = LackState()
private val sufficient = SufficientState()
}
private var state: State = lack
private var money = 0
override fun coin() {
state.coin(this)
}
override fun push() {
state.push(this)
}
fun warningMessage() {
println("これ以上の入金は不要です。")
}
fun errorMessage() {
println("必要な金額が投入されていません。")
}
fun insertMoney(m: Int) {
println("お金を投入しました。")
money += m
if (money >= 100) {
state = sufficient
}
}
fun buy() {
println("飲み物を取り出し口からお取りください。")
state = lack
}
}
###使う人
package state
class Client {
init {
val v: Context = VendingMachine()
v.coin()
v.push()
v.coin()
v.coin()
v.push()
}
}
###出力結果
[out-put]
お金を投入しました。
必要な金額が投入されていません。
お金を投入しました。
これ以上の入金は不要です。
飲み物を取り出し口からお取りください。
Context
型のVendingMachine
クラスのインスタンスを生成するFactory
クラスを実装するとよりよくなると思います。