我有一个特性DbClientUtil,如下所示:
trait DbClientUtil{
lazy val dbClient = //Initializing client here
}
我有一个Dbhelper对象,它扩展了DbClientUtil特性,如下所示:
object DbHelper extends DbClientUtil{
def sendDbPayload(dbModel:DbModel):Unit = {
dbClient.sendData(dbModel)
}
}
在上面给出的示例中sendData
是dbClient
上的方法。
现在我想迭代一个集合,将元素转换为模型,将其发送到数据库,然后关闭客户端。
所以,我在下面的对象
中写出了这个策略object Runner extends DbClientUtil{
import DbHelper._
List(DbModel("model1"),DbModel("model2"),DbModel("model3")).foreach{
model => sendDbPayload(model)
}
dbClient.shutdown
}
我有两个扩展相同特征的对象。 DBHelper
和Runner
扩展了相同的特征DbClientUtil
。 DbClientUtil
初始化dbClient
。 dbClient
和DbHelper
正在使用已初始化的Runner
。我的问题是,我是否正在初始化dbClient
两次?我的下一个问题是,如果我将它初始化两次,那么更好的方法是重写它以防止任何多余的初始化?
由于
答案 0 :(得分:2)
其实是的。 DbClientUtil初始化两次:首先是DbHelper,然后是Runner。如果这是一个问题,有很多方法可以解决这个问题:
1)使DbClientUtil
无状态并将其重写为def dbClient
。它实际上是一个很好的解决方案,因为您的状态应该存储在数据库中而不依赖于您实例化的客户端数量
2)创建单身人士。只有一个。不是两个:
object DbClientUtil extends DbClientUtil
object DbHelper extends DbClientUtil{
def sendDbPayload(dbModel:DbModel):Unit = {
DbClientUtil.sendData(dbModel)
}
}
object Runner {
List(DbModel("model1"),DbModel("model2"),DbModel("model3")).foreach{
model => DbHelper.sendDbPayload(model)
}
DbHelper.shutdown //Use just one client, not two
}
但实际上我不喜欢这个。严格的依赖关系为您提供了更多的耦合
3)使用依赖注入。我想这是大型项目的最佳解决方案之一。例如,您可以使用Google Guice:
trait DbClientService {
def sendData(data: Any): Unit //No implementation
}
class DbClientServiceImpl extends DbClientService
def sendData(data: Any): Unit {
//write you implementation code
}
}
绑定它: https://github.com/codingwell/scala-guice/
class ServiceModule extends AbstractModule {
protected def configure() {
bind[DbClientService].to[DbClientServiceImpl].in[Singleton]
}
}
然后注入它:
class DbHelper @Inject()(dbClient:DbClientService) extends DbClientUtil{
def sendDbPayload(dbModel:DbModel):Unit = {
dbClient.sendData(dbModel)
}
}
class Runner @Inject()(dbClient:DbClientService) extends DbClientUtil{
List(DbModel("model1"),DbModel("model2"),DbModel("model3")).foreach{
model => dbClient.sendDbPayload(model)
}
dbClient.shutdown
//still, don't know if it is good solution
//to control client state from outer scope
//better make this logic private
}