Scala、蛋糕图案和MacWire

Scala、蛋糕图案和MacWire,scala,dependency-injection,Scala,Dependency Injection,我已经使用cake模式实现了一个电子邮件服务。下面是电子邮件组件,它提供了设置电子邮件正文样式的功能: trait EmailComponent { def body: Body trait Body { def style(content Html): Html } } trait DefaultEmailComponent extends EmailComponent { def body = new DefaultBody class DefaultBod

我已经使用cake模式实现了一个电子邮件服务。下面是
电子邮件组件
,它提供了设置电子邮件正文样式的功能:

trait EmailComponent {
  def body: Body

  trait Body {
    def style(content Html): Html
  }
}

trait DefaultEmailComponent extends EmailComponent {
  def body = new DefaultBody

  class DefaultBody extends Body {
    views.html.email(content)
  }
}
。。。下面是使用
EmailComponent
实际实现电子邮件服务的
EmailServiceComponent

trait EmailServiceComponent {
  def emailService: EmailService

  trait EmailService {
    def sendEmail(from: String, recipients: Seq[String], subject: String, content: Html)
  }
}

trait DefaultEmailServiceComponent extends EmailServiceComponent {
  this: EmailComponent =>

  def emailService = new DefaultEmailService

  class DefaultEmailService extends EmailService {
    def sendEmail(from: String, recipients: Seq[String], subject: String, content: Html) {
      val htmlBody = body.style(content)
      EmailHelper.sendEmail(from, recipients, Some(subject), (None, Some(htmlBody)))
    }
  }

上面的代码运行良好。。。但是当我在网上冲浪的时候,我遇到了MacWire。我到处阅读一些文档,发现非常有趣,但老实说,我还没有完全理解如何使用它以及它是如何工作的。话虽如此,我如何用MacWire重新实现上述示例

需要考虑的几件事:

  • 一个很大的区别是,示例中的cake模式使用继承/类组合来满足依赖项并构建具体实例,而使用依赖项注入时,您将主要使用委托。由您决定希望类之间的紧密耦合程度

  • 使用定义的特征时,MacWire对布线有限制 内在的其他特质。因此,您的
    默认…
    实现必须 超越父母的特质

  • 快速一看,MacWire似乎无法解决具体问题 trait的实现(与Guice不同,Guice是一种成熟的 Java依赖注入框架,您可以使用 绑定和注释)。这意味着您必须使用
    wire[DefaultEmailService]
    而不是
    wire[EmailService]

  • MacWire中不支持循环依赖项。在上面的例子中,您无论如何都没有它们:EmailServiceComponent依赖于EmailService,而EmailService又依赖于EmailComponent

  • 因此,使用MacWire,您的代码将只是使用其他类的类,如

    class DefaultEmailComponent extends EmailComponent { ... }
    class DefaultEmailService(emailComponent: EmailComponent) extends EmailService { ... }
    trait EmailServiceComponent {
        def emailService: EmailService
    }
    class DefaultEmailServiceComponent(val emailService: EmailService) 
                                                  extends EmailServiceComponent { ... }
    
    lazy val emailC: EmailComponent = wire[DefaultEmailComponent]
    lazy val emailSvc: EmailService = wire[DefaultEmailService]
    lazy val emailSvcC: EmailServiceComponent = wire[DefaultEmailServiceComponent]
    

    非常感谢您的解释:-)如果我在MacWire行话中没有错的话,“组件”是“模块”,不是吗?根据他们的维基,MacWire模块中有任何Scala特性、类或对象,如3,关键是MacWire不必做任何扫描等-您只需指定哪些类应用于布线。因此,您必须在某一点上指定将哪个类用作特定特性/接口的实现,该特性/接口在其他地方“注入”。为了防止有人真的必须处理循环依赖关系,按名称调用依赖关系将有所帮助