I am searching for a design pattern/way to exchange a (persistence) layer of my application dynamically (preferably even at runtime).
Why?
I'd like to be able to decide whether to save certain data to XML or a database on a "per instance"-basis. So I may decide that one project uses XML as a backend and another uses a database. I want to be flexible here and to be able to easily add another "driver" for e.g. Json or whatever.
Now assume the following setup:
We have a controller and we want to manage some data. We can choose between a SQL and XML implementation.
One possible (working) solution:
BasicController.scala
val myPersistenceLayer: PersistenceLayer = SQLPersistenceLayer
val apples: Seq[Apple] = myPersistenceLayer.getApples()
trait PersistenceLayer
{
def getApples(): Seq[Apple]
def getBananas(): Seq[Banana]
}
object SQLPersistenceLayer extends PersistenceLayer
{
override def getApples(): Seq[Apple] = {...}
override def getBananas(): Seq[Banana] = {...}
}
This is a rather nasty solution as one would have to add methods for each new Model (think fruit! ;)) not only in the trait, but also in every implementation. I like my single responsibility so I'd rather delegate that to the models instead, like:
trait PersistenceLayer
{
def getAll(model: Model): Seq[Model] = { model.getAll() }
}
trait Model
{
def getAll(): Seq[Model]
}
package "SQL"
class Apple extends Model
{
def getAll(): Seq[Apple] = { // do some SQL magic here }
}
package "XML"
class Apple extends Model
{
def getAll(): Seq[Apple] = { // do some XML magic here instead }
}
Now the big problem here is, even if I implement a concrete PersistenceLayer, like so:
object SQLPersistenceLayer extends PersistenceLayer {}
how could I tell the application to use the model of the right package?
If I use the SQLPersistenceLayer upon:
val apples = myPersistenceLayer.get(Apple)
I would need to import the right "Apple" class, which defeats the whole purpose because then I could just remove all other classes, import the right one and just use a generic "getAll()" method on it.
So again I would need to change the implementation at multiple lines, which is what I want to avoid.
I thought about something like giving a string with the package-name, like
val package = "sql" and in the controller to import it from the right package, but this is not really feasible and not really easy to accomplish and it's a rather nasty hack for something I'm obviously missing.
To make a long story short: I want to be able to switch the package to use for my persistence needs dynamically. In some dynamically typed languages I could come up with a solution, but not in Scala or any statically typed language, so I guess I'm not knowing a certain design pattern here
Aucun commentaire:
Enregistrer un commentaire