LoginSignup
0
0

【Gang of Four】State

Last updated at Posted at 2019-12-01

#State
目次

よくXXXStatusのような状態を管理するプロパティを持たせ、switch(XXXStatus){ // caseにより色々な処理を行う }ような実装をすることがあると思います。
状態が増えるとswitch文が長々と続くことになり読む側も大変になっていくのを、状態1つ1つをオブジェクトにすることによりスマートにしようというのが本パターンの主旨だと考えています。

##目的
オブジェクトの内部状態が変化したときに、オブジェクトが振る舞いを変えるようにする。クラス内では、振る舞いの変化を記述せず、状態を表すオブジェクトを導入することでこれを実現する。

##構成要素
・Context 色々な状態があるクラス
・State 状態の抽象クラス
・ConcreteState 状態の具象クラス

##実装
自動販売機を実装することにします。
実装する自動販売機の状態としては以下の2つの状態と2つの操作があることと、商品の価格は一律100円とします。
状態
・商品の価格未満の金額が入金されている。
・商品の価格以上の金額が入金されている。

操作
・入金する。
・商品のボタンを押す。

###State 状態の抽象クラス

State.kt
package state

interface State {
    fun coin(v: VendingMachine)
    fun push(v: VendingMachine)
}

###ConcreteState 状態の具象クラス
商品の価格未満の金額が入金されている状態を表すクラス

LackState.kt
package state

class LackState: State {
    override fun coin(v: VendingMachine) {
        v.insertMoney(50)
    }

    override fun push(v: VendingMachine) {
        v.errorMessage()
    }
}

商品の価格以上の金額が入金されているクラス

SufficientState.kt
package state

class SufficientState: State {
    override fun coin(v: VendingMachine) {
        v.warningMessage()
    }

    override fun push(v: VendingMachine) {
        v.buy()
    }

}

###Context 色々な状態があるクラス
抽象クラス

Context.kt
package state

interface Context {
    fun coin()
    fun push()
}

自動販売機具象クラス

VendingMachine.kt
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
    }
}

###使う人

Client.kt
package state

class Client {
    init {
        val v: Context = VendingMachine()
        v.coin()
        v.push()
        v.coin()
        v.coin()
        v.push()
    }
}

###出力結果

[out-put]
お金を投入しました。
必要な金額が投入されていません。
お金を投入しました。
これ以上の入金は不要です。
飲み物を取り出し口からお取りください。

Context型のVendingMachineクラスのインスタンスを生成するFactoryクラスを実装するとよりよくなると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0