2016-04-12 8 views
2

Ich versuche, das Beispiel von diesem blog zu folgen. Ich verstehe das Beispiel, habe aber Probleme bei der Implementierung.Scala Kuchen Muster & Selbst Typ Anmerkungen

trait Database { 
    // ... 
} 

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

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

Das Beispiel erwähnt, dass die vollständige Datenbank-Funktionalität wird von dem Emailservice versteckt werden - das ist, was ich nach, aber nicht wissen, wie diese Eigenschaften korrekt umzusetzen.

Das ist, was ich zu implementieren versucht:

mir
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" 
    } 
    } 

Es sieht seltsam becasue MongoDatabase Merkmal nicht für find Umsetzung gefragt hat und wenn ich EmailService umgesetzt wurde ich dann für find Implementierung gefragt werden, obwohl das Beispiel dies erwähnt wird von der versteckt werden. Was fehlt mir hier?

Nachdem ich Ihre Kommentare gelesen habe, versuche ich zu implementieren, was ich versuche zu verstehen, an einem Beispiel, das näher an dem ist, was ich eigentlich versuche.

Der erste Snippet wird nicht kompiliert, aber der zweite wird ... Am Ende des Tages ich verschiedene Repository Implementierungen haben wollen, wo ich zwischen den Datenbanken auf sie verlassen wechseln können, bin ich mit einem in der Nähe der Schnipsel unten?

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' erstreckt' MongoUserDb' die 'MongoDatabase' erstreckt, die' Database' erstreckt. Irgendwo in dieser Hierarchie muss es eine Implementierung von 'find' geben (weil' EmailServiceImpl' nicht abstrakt ist). Es hat nichts mit den Anmerkungen vom Typ selbst oder dem Kuchenmuster zu tun. – Jesper

+0

Ich verstehe .. Ich lerne nur dieses Thema und der Blog war nicht so klar (zumindest für mich). – Killyz

+0

Hast du einen Blick auf den Code geworfen, den ich gepostet habe? Das könnte deinen Zweck erfüllt haben, glaube ich. –

Antwort

1

Wie erwähnt MongoUserDB wird nicht für eine Implementierung als ein trait fragen. Jedoch seit EmailServiceImplextends die Eigenschaft, die es benötigt, um eine Implementierung bereitzustellen. Was Sie suchen, könnte getan werden, indem Sie eine weitere Abstraktion hinzufügen. Ich mache es mit der und DAO Architektur. Unten finden Sie ein Arbeitsbeispiel, mit dem Sie sehen können, ob es für Sie geeignet ist.

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

Hier ist der Code, den Sie implementieren möchten könnte,

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

Wo implementieren Sie hier die eigentlichen CRUDs der Datenbank? – Killyz

+0

Innerhalb der 'ConcreteDAO' und' ConcreteDAO1'. Anstelle der Methoden 'getRecords' und' updateRecords' implementieren Sie die CRUD-Methoden. –

1

Database aus EnailService versteckt, aber nicht von EmailServiceImpl. Letzteres ist eine Unterklasse von MongoUserDB, offensichtlich hat es Zugriff darauf. MongoUserDB fragt nicht nach find Implementierung, weil es ein Merkmal ist, und Eigenschaften können abstrakte Methoden haben. Sie sollten es immer noch dort implementieren, auch ohne gefragt zu werden;)

+0

ich sehe .. Was ist mit der Art, wie ich Dinge implementiert .. würden Sie etwas ändern? – Killyz

+0

Weiß nicht, ohne die Besonderheiten der APIs zu kennen, macht es insgesamt Sinn ...'MongoUserDb' scheint ein wenig redundant zu sein, würde ich wahrscheinlich damit aufhören, und habe nur' Klasse EmailServiceImpl erweitert EmailService mit UserDb mit MongoDatabase' stattdessen. Abgesehen davon LGTM. – Dima

+0

Ich bin damit einverstanden .. in einem echten API Ich möchte ein 'Database',' Repository' & 'Service' Züge implementieren, wo' Repository' wird mit einer 'Database' Implementierung und die' Service' ist die Implementierung Sie mit interagieren würde. – Killyz