2012年4月17日火曜日

【Scala】コンストラクタ実装したtraitをobjectにmixinしたらなるほど、こうなるよな、という話

あるリクエストを受け取ったときに、ユーザに関連する情報を一括で削除したい、という要件があった。

対象のテーブルがたくさんあったので、いちいちhoge.deleteみたいな記述を羅列するのは避けたい。削除対象テーブルは今後の開発で余裕で増えるだろうし。

で、こんなコードを書いてみた。

    object CleanerContainer {
        import scala.collection.mutable.ListBuffer
        private val list: ListBuffer[Cleaner] = new ListBuffer[Cleaner]

        def append(cleaner: Cleaner) = this.list.append(cleaner) 

        def execute(userId: String): Unit = list.foreach(_.clean(userId))
    }

    /**
    * コンストラクタで自分自身をCleanerContainer に追加するので、
    * これをmixinするだけでCleanerContainer.executeの処理対象になるはず。
    */
    trait Cleaner {
        CleanerContainer.append(this)

        def clean(userId: String): Unit
     }

     /** DBのCRUDを実装したmodelのコンパニオンオブジェクトと仮定  */
     object hogeModel extends Cleaner {
         override def clean(userId: String) = {
             hoge.delete(userId)
         }
         // (以下の実装は省略)
     }

CleanContainerは、一括削除の対象となるmodelをListで保有し、executeでそれらのcleanメソッドをまとめて実行する。

CRUDを実装しているmodelのコンパニオンオブジェクトが、Cleanerというtraitをmixinすることで、Cleanerのコンストラクタで自分自身をCleanContainerに追加しているから、hogeModelのようにclean関数に自信の対象レコードを削除する処理を記述すれば、CleanContainer.executeを任意のタイミングで実行することで、対象のデータを一括で削除できるはず!!!

で、意気揚々と実行してみたが、全然データが消えない。

…あ! objectにmixinしたtraitのコンストラクタ実装って、objectが最初に呼ばれたタイミングでないと実行されないじゃん!! シングルトンオブジェクトなんだからそりゃそうじゃん!!!

てっきりobjectってアプリケーションが起動したタイミングでオブジェクトが生成されるものだと勘違いしていたという、失敗談でした……。

0 件のコメント:

コメントを投稿