LoginSignup
0
0

【Gang of Four】Visitor

Last updated at Posted at 2019-12-01

#Visitor
目次
訪問者に全ての要素に対するインターフェースを用意しておき、その要素に関する処理を訪問者にやってもらうというパターンだと理解しています

##目的
あるオブジェクト構造上の要素で実行されるオペレーションを表現する。Visitor パターンにより、オペレーションを加えるオブジェクトのクラスに変更を加えずに、新しいオペレーションを定義することができるようになる

##構成要素
・Visitor 訪問者抽象クラス
・ConcreteVisitor 訪問者具象クラス
・Element 訪問者に処理を移譲する要素の抽象クラス
・ConcreteElement 訪問者に処理を移譲する要素の具象クラス
・ObjectStructure 要素を列挙することができるクラス(らしいんですが必要性を理解できていません)

##実装
用意された材料を使って料理を作るプログラムを実装します。

###Visitor 訪問者抽象クラス

Visitor.kt
package visitor

interface Visitor {
    fun visit(e: PotatoElement)
    fun visit(e: CarrotElement)
    fun visit(e: PorkElement)
    fun visit(e: OtherElement)
    fun serve()
}

###ConcreteVisitor 訪問者具象クラス

カレーを作る訪問者

CurryVisitor.kt
package visitor

class CurryVisitor: Visitor {
    private var cookingPotato = false
    private var cookingCarrot = false
    private var cookingPork = false
    private var cookingOther = false

    override fun visit(e: PotatoElement) {
        cookingPotato = true
        println("${e.name()}の皮を剥いて切って鍋で煮込みます。")
    }

    override fun visit(e: CarrotElement) {
        cookingCarrot = true
        println("${e.name()}の芽をとって皮を剥いて切って鍋で煮込みます。")
    }

    override fun visit(e: PorkElement) {
        cookingPork = true
        println("${e.name()}を切って鍋で煮込みます。")
    }

    override fun visit(e: OtherElement) {
        cookingOther = true
        println("カレーのルーと${e.name()}を鍋に入れて煮込みます。")
    }

    override fun serve() {
        if (cookingPotato && cookingCarrot && cookingOther && cookingPork) {
            println("カレーの完成!")
        } else {
            println("まだ料理中です。")
        }
    }

}

###Element 訪問者に処理を移譲する要素の抽象クラス
材料抽象クラス

Element.kt
package visitor

interface Element {
    fun name(): String
    fun cooking(v: Visitor)
}

###ConcreteElement 訪問者に処理を移譲する要素の具象クラス
材料具象クラスたち
じゃがいも

PotatoElement.kt
package visitor

class PotatoElement: Element {
    override fun name(): String {
        return "じゃがいも"
    }

    override fun cooking(v: Visitor) {
        v.visit(this)
    }
}

にんじん

CarrotElement.kt
package visitor

class CarrotElement: Element {
    override fun name(): String {
        return "にんじん"
    }

    override fun cooking(v: Visitor) {
        v.visit(this)
    }
}

豚肉

PorkElement.kt
package visitor

class PorkElement: Element {
    override fun name(): String {
        return "豚肉"
    }

    override fun cooking(v: Visitor) {
        v.visit(this)
    }

}

その他

OtherElement.kt
package visitor

class OtherElement: Element {
    override fun name(): String {
        return "塩と胡椒"
    }

    override fun cooking(v: Visitor) {
        v.visit(this)
    }
}

###使う人

Client.kt
package visitor

class Client {
    init {
        serveCurry()
    }

    private fun serveCurry() {
        val pot = PotatoElement()
        val c = CarrotElement()
        val por = PorkElement()
        val o = OtherElement()
        val v = CurryVisitor()

        pot.cooking(v)
        c.cooking(v)
        por.cooking(v)
        v.serve()
        o.cooking(v)
        v.serve()
    }
}
[out-put]

じゃがいもの皮を剥いて切って鍋で煮込みます。
にんじんの芽をとって皮を剥いて切って鍋で煮込みます。
豚肉を切って鍋で煮込みます。
まだ料理中です。
カレーのルーと塩と胡椒を鍋に入れて煮込みます。
カレーの完成!

野菜炒めを作りたくなったのでFriedVegetablesVisitorを実装します。

FriedVegetablesVisitor.kt
package visitor

class FriedVegetablesVisitor: Visitor {
    private var cookingPotato = false
    private var cookingCarrot = false
    private var cookingPork = false
    private var cookingOther = false

    override fun visit(e: PotatoElement) {
        cookingPotato = true
        println("${e.name()}の皮を剥いて切って炒めます。")
    }

    override fun visit(e: CarrotElement) {
        cookingCarrot = true
        println("${e.name()}の芽をとって皮を剥いて切って炒めます。")
    }

    override fun visit(e: PorkElement) {
        cookingPork = true
        println("${e.name()}を切って炒めます。")
    }

    override fun visit(e: OtherElement) {
        cookingOther = true
        println("${e.name()}を鍋に入れて炒めます。")
    }

    override fun serve() {
        if (cookingPotato && cookingCarrot && cookingOther && cookingPork) {
            println("野菜炒めの完成!")
        } else {
            println("まだ料理中です。")
        }
    }
}
Client.kt
package visitor

class Client {
    init {
        serveCurry()
        println("--------------------------------")
        serveFriedVegetables()
    }

    private fun serveFriedVegetables() {
        val pot = PotatoElement()
        val c = CarrotElement()
        val por = PorkElement()
        val o = OtherElement()
        val v = FriedVegetablesVisitor()

        pot.cooking(v)
        c.cooking(v)
        por.cooking(v)
        v.serve()
        o.cooking(v)
        v.serve()
    }

    private fun serveCurry() {
        val pot = PotatoElement()
        val c = CarrotElement()
        val por = PorkElement()
        val o = OtherElement()
        val v = CurryVisitor()

        pot.cooking(v)
        c.cooking(v)
        por.cooking(v)
        v.serve()
        o.cooking(v)
        v.serve()
    }
}

###出力結果

[out-put]
じゃがいもの皮を剥いて切って鍋で煮込みます。
にんじんの芽をとって皮を剥いて切って鍋で煮込みます。
豚肉を切って鍋で煮込みます。
まだ料理中です。
カレーのルーと塩と胡椒を鍋に入れて煮込みます。
カレーの完成!
--------------------------------
じゃがいもの皮を剥いて切って炒めます。
にんじんの芽をとって皮を剥いて切って炒めます。
豚肉を切って炒めます。
まだ料理中です。
塩と胡椒を鍋に入れて炒めます。
野菜炒めの完成!
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