Scala Best Practices: Trait Inheritance vs Enumeration

…衆ロ難τιáo~ 提交于 2019-12-02 22:22:49
Daniel C. Sobral

If you declare a sealed trait DBType, you can pattern match on it with exhaustiveness checking (ie, Scala will tell you if you forget one case).

Anyway, I dislike Scala's Enumeration, and I'm hardly alone in that. I never use it, and if there's something for which enumeration is really the cleanest solution, it is better to just write it in Java, using Java's enumeration.

For this particular case you don't really need classes for each database type; it's just data. Unless the real case is dramatically more complex, I would use a map and string parsing based solution to minimize the amount of code duplication:

case class DBRecord(url: String, driver: String, adapter: () => DatabaseAdapter) {}

class DBType(record: DBRecord) {
  lazy val driver = Class.forName(record.driver).newInstance().asInstanceOf[Driver]
  lazy val adapter = record.adapter()
}

object DBType {
  val knownDB = List(
    DBRecord("mysql", "com.mysql.jdbc.Driver", () => new MySQLAdapter),
    DBRecord("postgresql", "org.postgresql.Driver", () => new PostgreSqlAdapter),
    DBRecord("h2", "org.h2.Driver", () => new H2Adapter)
  )

  val urlLookup = knownDB.map(rec => rec.url -> rec).toMap

  def fromURL(url: String) = {
    val parts = url.split(':')
    if (parts.length < 3 || parts(0) != "jdbc") None
    else urlLookup.get(parts(1)).map(rec => new DBType(rec))
  }
}

I'd go for the singleton variant, since it allows clearer subclassing.

Also you might need to do db-specific things/overrides, since some queries/subqueries/operators might be different.

But i'd try something like this:

import org.squeryl.internals.DatabaseAdapter
import org.squeryl.adapters.{H2Adapter, MySQLAdapter, PostgreSqlAdapter}
import java.sql.Driver

abstract class DBType(jdbcDriver: String) {
  lazy val driver = Class.forName(jdbcDriver).newInstance().asInstanceOf[Driver]
  def adapter: DatabaseAdapter
}


object DBType {
  object MySql extends DBType("com.mysql.jdbc.Driver") {
    lazy val adapter = new MySQLAdapter
  }

  object PostgreSql extends DBType("org.postgresql.Driver") {
    lazy val adapter = new PostgreSqlAdapter
  }

  object H2 extends DBType("org.h2.Driver") {
    lazy val adapter = new H2Adapter
  }

  def fromUrl(url: String) = {
    url match {
      case _ if url.startsWith("jdbc:mysql:") => Some(MySql(url))
      case _ if url.startsWith("jdbc:postgresql:") => Some(PostgreSql(url))
      case _ if url.startsWith("jdbc:h2:") => Some(H2(url))
      case _ => None
    }

}

if this helped, please consider to +1 this :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!