2013-01-09 14 views
0

我試圖首次使用蛋糕模式。僅替換全局蛋糕模式應用程序中的存儲庫

我有點理解它是如何工作的,但想知道是否可以混合已經混合的特徵或類似的東西。

我想要的是用蛋糕模式構建一個全局應用程序。 而且我希望該應用程序的另一個版本可以是相同的,除了在存儲庫級別。

是否有可能做這樣的事情:

trait application extends DefaultUserServiceComponent with MongoUserRepositoryComponent 

    object realApplication extends application 
    object fakeApplication extends FakeUserRepositoryComponent with application 

我的意思是:再利用已建成的應用來說,使用假倉庫假的應用程序時?

回答

2

簡答:不會。您會繼承衝突成員。請看下面的代碼片段:

trait Repository {def authenticate(username: String, password: String): String} 

trait UserServiceComponent {self: UserRepositoryComponent => 
    val userService: UserService = new UserService 
    class UserService { 
    def authenticate(username: String, password: String): String = 
     repository.authenticate(username, password) 
    } 
} 

trait UserRepositoryComponent { 
    def repository: Repository 
} 

trait MongoUserRepositoryComponent extends UserRepositoryComponent { 
    val repository: Repository = 
    new Repository {def authenticate(username: String, password: String) = "MongoAuthed"} 
} 

trait MockUserRepositoryComponent extends UserRepositoryComponent { 
    val repository: Repository = 
    new Repository {def authenticate(username: String, password: String) = "MockAuthed"} 
} 

trait Application extends UserServiceComponent with MongoUserRepositoryComponent 

object RealApplication extends Application 
// The following will be an error: "object FakeApplication inherits conflicting members:" 
object FakeApplication extends Application with MockUserRepositoryComponent 

相反,有需要的行爲,定義應用這樣:

trait Application extends UserServiceComponent {self: UserRepositoryComponent =>} 
object RealApplication extends Application with MongoUserRepositoryComponent 
object FakeApplication extends Application with MockUserRepositoryComponent 

要保持在OP給出的層次結構,則需要修改代碼,例如:

trait MongoUserRepositoryComponent extends UserRepositoryComponent { 
    private val _repository = new Repository {def authenticate(username: String, password: String) = "MongoAuthed"} 
    def repository: Repository = _repository 
} 

trait MockUserRepositoryComponent extends UserRepositoryComponent { 
    private val _repository = new Repository {def authenticate(username: String, password: String) = "MockAuthed"} 
    def repository: Repository = _repository 
} 

trait Application extends UserServiceComponent with MongoUserRepositoryComponent 

object RealApplication extends Application 
object FakeApplication extends Application with MockUserRepositoryComponent { 
    override val repository: Repository = super[MockUserRepositoryComponent].repository 
} 

附加private val _repository的是必要的,這樣我們可以定義repository作爲函數,因此它可被用作在超控。 (使用super[type]覆蓋僅適用於函數)。

編輯:最後,cake模式的目的是開發一個層次結構,其中不需要像我提供的最後一個代碼段那樣重寫。實際上,Application不應該存在,只有RealApplicationFakeApplication。 (在第二個代碼片段中,我基本上只是將UserServiceComponent更改爲Application)。

+1

被編輯爲使其更「cakey」,並更類似http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/這是一個很好的參考蛋糕模式(順便說一句,在你的問題中給出的例子) –

+0

你能檢查這個問題嗎? :) http://stackoverflow.com/questions/14532368/cake-pattern-one-component-per-implementation-or-one-component-per-trait –