2016-04-12 7 views
2

私はこのblogの例に従おうとしています。私はその例を理解していますが、実装には問題があります。スカラケーキパターンとセルフタイプの注釈

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実装を求めていなかったと私はEmailServiceを実装したとき、私はその後、find実装のために促されたbecasueそれは私には奇妙に見えますEmailServiceからは非表示になります。私はここで何が欠けていますか?

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

最初のスニペットはコンパイルされません

が、2番目の1人の意志...私は、彼らが依存しているデータベースを切り替えることができます異なるRepository実装を持ちたい一日の終わりに は、私は1つを閉じています下のスニペットの

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" 
     } 
    } 
    } 
+0

'EmailServiceImpl'は' 'Database'を拡張' MongoDatabase'を拡張MongoUserDb'を拡張します。その階層のどこかに 'find'の実装がなければなりません(' EmailServiceImpl'は抽象的ではないので)。それは、自己型注釈やケーキパターンとは関係ありません。 – Jesper

+0

私は理解しています。私はこの話題を学んでいるだけで、ブログはそのことを(少なくとも私にとっては)明確ではありませんでした。 – Killyz

+0

あなたは私が投稿したコードを見ましたか、それは私が信じるあなたの目的を果たした可能性があります。 –

答えて

1

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

//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) 

} 

EDIT ---ここ

はあなたが実装する可能性のあるコードで、

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 
    } 
+0

ここで実際のデータベースCRUDはどこに実装していますか? – Killyz

+0

「ConcreteDAO」と「ConcreteDAO1」の内部メソッド 'getRecords'と' updateRecords'の代わりにCRUDメソッドを実装します。 –

1

DatabaseEnailServiceからではなく、EmailServiceImplから隠されています。後者はMongoUserDBのサブクラスで、明らかにアクセス権があります。 MongoUserDBfindの実装に「問い合わせ」しません。これは特性であり、特性は抽象メソッドを持つことができるためです。それでも依頼されなくても実装する必要があります)

+0

私は..を参照してください。 私は物事を実装した方法については何か..あなたは何かを変更しますか? – Killyz

+0

Dunnoは、APIの仕様を知らなくても、全体的に意味があります...'MongoUserDb'はちょっと冗長に思えるかもしれませんが、おそらくそれをやめて、代わりに' class EmailServiceImplがMongoDatabaseを使ってUserDbでEmailServiceを拡張するようにしてください。それ以外は、LGTM。 – Dima

+0

私は本当のAPIに同意します。 'Repository 'が' Database'実装を使用し、 'Service'があなたがやりとりする実装である' Database'、 'Repository'&' Service'特性を実装したいと思います。 。 – Killyz