蛋糕图案可以用于非单一样式的依赖关系吗? [英] Can the Cake Pattern be used for non-singleton style dependencies?

查看:60
本文介绍了蛋糕图案可以用于非单一样式的依赖关系吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到的大多数蛋糕模式示例似乎都将依赖项视为单例类型服务;在组件的最终组装中,每种类型只有一个实例。当使用Cake Pattern进行依赖注入时,是否可以编写一个具有多个特定类型实例的配置,也许以不同的方式配置?

Most of the examples of the Cake Pattern I've come across appear to consider dependencies as singleton type services; where there is only one instance of each type in the final assembly of components. Is it possible to write a configuration that has more than one instance of a particular type, perhaps configured in different ways, when using the Cake Pattern for dependency injection?

考虑一下以下组件。通用HTTP服务:

Consider the following components. Generic HTTP service:

trait HttpService { def get(query:String):String }
trait HttpServiceComponent {
  val httpService:HttpService
  class HttpServiceImpl(address:String) extends HttpService {
    def get(query:String):String = ...
  }
}

贸易与交易公司服务,每个服务都依赖于HttpService,这可能是不同的实例:

Trade & Company services, that each depend on an HttpService, which may be different instances:

trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
  this:HttpServiceComponent => // Depends on HttpService
  val tradeService:TradeService
  class TradeServiceImpl extends TradeService {
    def lastTrade(symbol:String):String =
      httpService.get("symbol=" + symbol)
  }
}

trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
  this:HttpServiceComponent =>  // Depends on different HttpService instance
  val companyService:CompanyService
  class CompanyServiceImpl extends CompanyService {
    def getCompanySymbols(exchange:String):String =
      httpService.get("exchange=" + exchange)
  }
}

主要应用组件取决于Trade& ;公司服务:

Main app component that depends on Trade & Company services:

trait App { def run(exchange:String):Unit }
trait AppComponent {
  this:CompanyServiceComponent with TradeServiceComponent =>
  val app:App
  class AppImpl extends App {
    def run(exchange:String) =
      companyService.getCompanySymbols(exchange).split(",").foreach(sym => {
        val lastTrade = tradeService.lastTrade(sym)
        printf("Last trade for %s: %s".format(sym, lastTrade))
      })
  }
}

是否可以连接该应用程序,以便其TradeService使用

Is it possible to wire up the App so that its TradeService uses a HttpService that points to one address, and its CompanySerivce uses a different HttpService instance pointing to another address?

推荐答案

指向一个地址的HttpService指向其地址,而CompanySerivce使用另一个指向另一个地址的HttpService实例?答案(特别是丹尼尔的答案,也可以是您自己的答案),虽然可以,但看起来并不优雅。出现困难的原因是,当您使用Cake模式时,您将所有必需的特征混合到一个对象中(使用 with关键字),并且不能将一个特征多次混合到一个实例中。这就是mixins的工作方式,而Cake就是基于它们的。

As you can see from the answers (notably Daniel's, but also your own), it is possible, but it doesn't look elegant. The difficulty appears because when you use the Cake pattern, you mix all required traits into one object (using "with" keyword), and you cannot mix a trait more than once into one instance. That is how mixins work, and the Cake is based on them.

您可以强迫Cake处理非单一依赖项的事实并不意味着您应该这样做。在这种情况下,我建议您只使用普通的构造函数,这是自类型注释不太适合的地方:

The fact you can force Cake to handle non-singleton dependencies doesn't mean you should do it. I would advise you to simply use plain-old constructor in such cases, that is where self-type annotation doesn't fit well:

trait HttpService { ... }

/* HttpServiceImpl has become a top-level class now,
 * as the Cake pattern adds no more value here.
 * In addition, trait HttpServiceComponent gets deleted */
class HttpServiceImpl(address:String) extends HttpService {
  ...
}

trait TradeService { def lastTrade(symbol:String):String }
trait TradeServiceComponent {
  // The dependency on HttpService is no longer declared as self-type
  val tradeService:TradeService
  // It is declared as a constructor parameter now
  class TradeServiceImpl(httpService: HttpService) extends TradeService {
    def lastTrade(symbol:String):String =
      httpService.get("symbol=" + symbol)
  }
}

trait CompanyService { def getCompanySymbols(exchange:String):String }
trait CompanyServiceComponent {
  // Again, self-type annotation deleted
  val companyService:CompanyService
  // Again, the dependency is declared as a constructor parameter
  class CompanyServiceImpl(httpService: HttpService) extends CompanyService {
    def getCompanySymbols(exchange:String):String =
      httpService.get("exchange=" + exchange)
  }
}

App和AppComponent特性保持其原始形式。现在,您可以通过以下方式使用所有组件:

The App and AppComponent traits stay in their original form. Now you can use the all components in the following way:

object App {
  def main(args:Array[String]):Unit = {
    val appAssembly = new AppComponent 
        with TradeServiceComponent
        with CompanyServiceComponent {
      // Note, that HttpServiceComponent it neither needed nor mixed-in now
      val tradeService = new TradeServiceImpl(
        new HttpServiceImpl("http://trades-r-us.com"))
      val companyService = new CompanyServiceImpl(
        new HttpServiceImpl("http://exchange-services.com"))
      val app = new AppImpl
    }
    appAssembly.app.run(args(0))
  }
}

此外,您可能需要仔细检查Cake模式是否真的最适合您的需求,因为它实际上是一个复杂的模式,依赖注入只是其中的一部分。如果仅将其用于DI,建议您使用更简单的解决方案。我已经在该博客中发布了这里

Also, you may want do double-check if the Cake pattern is really best suited for your needs, as it is actually a complex pattern and dependency injection is only one part of it. If you use it only for DI, I would advise you to use a simpler solution. I've blogged about that here.

这篇关于蛋糕图案可以用于非单一样式的依赖关系吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆