2

私はこのブログの例に従おうとしています。例は理解できますが、実装に問題があります。

trait Database {
  // ...
}

trait UserDb {
  this: Database =>
    // ...
}

trait EmailService {
  this: UserDb =>
    // Can only access UserDb methods, cannot touch Database methods
}

この例では、完全なデータベース機能が EmailService から隠されることに言及しています。これは私が求めているものですが、これらの特性を正しく実装する方法がわかりません。

これは私が実装しようとしたものです:

trait Database {
    def find(query: String): String
  }

  trait UserDb {
    this: Database =>
  }

  trait EmailService {
    this: UserDb =>
  }

  trait MongoDatabase extends Database {

  }

  trait MongoUserDb extends UserDb with MongoDatabase{

  }

  class EmailServiceImpl extends EmailService with MongoUserDb {
    override def find(query: String): String = {
      "result"
    }
  }

MongoDatabase トレイトが実装を要求しなかったため、私には奇妙にfind見えます。ここで何が欠けていますか?EmailServicefindEmailService

あなたのコメントを読んだ後、私が実際にやろうとしていることにより近い例で、理解しようとしていることを実装しようとしています。

最初のスニペットはコンパイルされませんが、2 番目のスニペットはコンパイルされます... 結局のところ、Repository依存しているデータベースを切り替えることができるさまざまな実装が必要です。

trait Database {
    def find(s: String): String
  }

  trait Repository {
    this: Database =>
  }

  class UserRepository extends Repository {
    def database = new MongoDB

    class MongoDB extends Database {
      def find(s: String): String = {
        "res"
      }
    }
  }


trait Repository {
    def database: Database

    trait Database {
      def find(s: String): String
    }
  }

  trait UserRepository extends Repository {
    def database = new MongoDB

    class MongoDB extends Database {
      def find(s: String): String = {
        "res"
      }
    }
  }
4

2 に答える 2

1

前述MongoUserDBのように、 a として実装を要求しませんtrait。ただしEmailServiceImpl extends、トレイトであるため、実装を提供する必要があります。探していることは、別の抽象化を追加することで実行できます。serviceandDAOアーキテクチャを使用してそれを行います。以下は、それがあなたに合っているかどうかを確認するために使用できる実際の例です。

//All future versions of DAO will extend this
trait AbstractDAO{
  def getRecords:String
  def updateRecords(records:String):Unit
}
//One concrete version
trait concreteDAO extends AbstractDAO{
  override def getRecords={"Here are DB records"}
  override def updateRecords(records:String){
    //Actual DB calls and operations
    println("Updated "+records)
  }
}
//Second concrete version
trait concreteDAO1 extends AbstractDAO{
  override def getRecords={"DB Records returned from DAO2"}
  override def updateRecords(records:String){
    //Actual DB calls and operations
    println("Updated via DAO2"+records)
  }
}
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that
trait service{
  this:AbstractDAO =>

  def updateRecordsViaDAO(record:String)={  
  updateRecords(record) 
  }
  def getRecordsViaDAO={
  getRecords
  }
}

//Test Stub
object DI extends App{
  val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods
  wiredObject.updateRecords("RECORD1")
  println(wiredObject.getRecords)

  val wiredObject1 = new service with concreteDAO1
  wiredObject1.updateRecords("RECORD2")
  println(wiredObject1.getRecords)

}

編集 - -

実装したいコードは次のとおりです。

    trait Database {
    def find(s: String): String
  }

trait MongoDB extends Database{
  def find(s:String):String = { "Test String" }
}
trait SQLServerDB extends Database{
  def find(s:String):String = { "Test String2" }
}

  trait Repository {
    this: Database =>
  }

  class UserRepository extends Repository with MongoDB{  //  UserRepository is injected with MongoDB here
    find("call MongoDB") //This call will go to the find method in MongoDB trait
  }

  class UserRepository1 extends Repository with SQLServerDB{  //  UserRepository is injected with SQLServerDB here
    find("call SQLServerDB") //This call will go to the find method in SQLServerDB trait
  }
于 2016-04-12T13:54:30.253 に答える
1

Database は から隠されていますEnailServiceが、 からは隠されていませんEmailServiceImpl。後者は のサブクラスでありMongoUserDB、明らかにアクセスできます。 これはトレイトであり、トレイトは抽象メソッドを持つことができるため、実装をMongoUserDB「要求」しません。find尋ねられなくても、そこに実装する必要があります;)

于 2016-04-12T13:22:35.517 に答える