日曜日, 12月 20, 2015

Scala - visitorパターンのようなもの

ScalaではVisitorパターンを割合簡潔に書くことが出来る.以下の例はあるデータベース上で接続・検索を実行するモジュールで,この例では通常のRDB, HiveそしてインメモリDBをサポートしているとする.また,(乱暴ではあるが簡略のために)RDBとHiveserver2はコネクトとクエリを同一の手順,インメモリはコネクトを必要としないと仮に想定している.


package tanuneko

/**
  * Created by neko32 on 2015/12/20.
  */
sealed abstract class DB(host:String, userId:String, passwd:String)

case class RegularRDB(host:String, userId:String, passwd:String) extends DB(host, userId, passwd)

case class InMemoryDB(userId:String, passwd:String) extends DB(null, userId, passwd)

case class HiveDB(host:String, userId:String, passwd:String) extends DB(host, userId, passwd)

case class ResultSet(data:String)

trait DBAction {
  def connect():Unit = {}
  def runQuery(str:String):ResultSet
}

class RegularDBAction(host:String, userId:String, passwd:String) extends DBAction {
  override def connect(): Unit = {
    println(s"connecting to ${host} with user[${userId}]")
  }
  override def runQuery(sql: String): ResultSet = {
    println(s"send query[${sql} to Database[${host}]")
    new ResultSet("returned data.")
  }
}

class InMemoryDBAction(userId:String, passwd:String) extends DBAction {
  override def runQuery(sql: String): ResultSet = {
    println(s"[inmem] running query[${sql}]")
    new ResultSet("returned data.")
  }
}

object Runner {
  def main(args:Array[String]):Unit = {
      val userId = "neko"
      val passwd = "miPasswd150X"
      val host = "myhost.org:16500"
      val sql = "select * from mydb.mytbl"

      def runQueryAfterConnect = (db:DB) => db match {
        case r:RegularRDB => {
          val act = new RegularDBAction(r.host, r.userId, r.passwd)
          act.connect()
          println(s"result - ${act.runQuery(sql)}")
        }
        case i:InMemoryDB => {
          val act = new InMemoryDBAction(i.userId, i.passwd)
          println(s"[inmem] result - ${act.runQuery(sql)}")
        }
        case r:HiveDB => {
          val act = new RegularDBAction(r.host, r.userId, r.passwd)
          act.connect()
          println(s"result - ${act.runQuery(sql)}")
        }
      }

      val sybase = new RegularRDB(host, userId, passwd)
      runQueryAfterConnect(sybase)
      val inmem = new InMemoryDB(userId, passwd)
      runQueryAfterConnect(inmem)
      val hive = new HiveDB(host, userId, passwd)
      runQueryAfterConnect(hive)
  }
}

0 件のコメント: