【问题标题】:What is the difference between an extension method, the builder pattern and the fluent interface?扩展方法、构建器模式和流畅接口之间有什么区别?
【发布时间】:2026-02-10 12:40:01
【问题描述】:

在 Scala 中 - 我们 can do 扩展方法如下:

object MyExtensions {
  implicit class RichInt(val i: Int) extends AnyVal {
    def square = i * i
  }
}

我们可以这样使用它:

import MyExtensions._
Int i = 2;
Val squared = i.square()
Val cubed = i.square().square()

我们可以像这样do the builder 模式:

sealed abstract class Preparation  
case object Neat extends Preparation
case object OnTheRocks extends Preparation
case object WithWater extends Preparation

sealed abstract class Glass
case object Short extends Glass
case object Tall extends Glass
case object Tulip extends Glass

case class OrderOfScotch(val brand:String, val mode:Preparation, val isDouble:Boolean, val glass:Option[Glass])

class ScotchBuilder {
  private var theBrand:Option[String] = None
  private var theMode:Option[Preparation] = None
  private var theDoubleStatus:Option[Boolean] = None
  private var theGlass:Option[Glass] = None

  def withBrand(b:Brand) = {theBrand = Some(b); this} /* returning this to enable method chaining. */
  def withMode(p:Preparation) = {theMode = Some(p); this}
  def isDouble(b:Boolean) = {theDoubleStatus = some(b); this}
  def withGlass(g:Glass) = {theGlass = Some(g); this}

  def build() = new OrderOfScotch(theBrand.get, theMode.get, theDoubleStatus.get, theGlass);
}



object BuilderPattern {
  class ScotchBuilder(theBrand:Option[String], theMode:Option[Preparation], theDoubleStatus:Option[Boolean], theGlass:Option[Glass]) {
    def withBrand(b:String) = new ScotchBuilder(Some(b), theMode, theDoubleStatus, theGlass)
    def withMode(p:Preparation) = new ScotchBuilder(theBrand, Some(p), theDoubleStatus, theGlass)
    def isDouble(b:Boolean) = new ScotchBuilder(theBrand, theMode, Some(b), theGlass)
    def withGlass(g:Glass) = new ScotchBuilder(theBrand, theMode, theDoubleStatus, Some(g))

    def build() = new OrderOfScotch(theBrand.get, theMode.get, theDoubleStatus.get, theGlass);
  }

  def builder = new ScotchBuilder(None, None, None, None)
}

我们可以这样使用它:

import BuilderPattern._

val order =  builder withBrand("Takes") isDouble(true) withGlass(Tall)  withMode(OnTheRocks) build()

我们可以这样do the fluent界面:

class Person {
    protected var fname = ""
    protected var lname = ""
    def setFirstName(firstName: String): this.type = {
        fname = firstName
        this
    }
    def setLastName(lastName: String): this.type = {
        lname = lastName
        this
    }
}

class Employee extends Person {
  protected var role = ""
  def setRole(role: String): this.type = {
      this.role = role
      this
  }
  override def toString = {
      "%s, %s, %s".format(fname, lname, role)
  }
}

我们可以这样使用它:

object Main extends App {
    val employee = new Employee
    // use the fluent methods
    employee.setFirstName("Al")
            .setLastName("Alexander")
            .setRole("Developer")
    println(employee)
}

这三个都为内部 DSL 提供了类似的接口。

我的问题是:扩展方法、构建器模式和流畅界面有什么区别?

【问题讨论】:

    标签: scala extension-methods fluent-interface builder-pattern


    【解决方案1】:

    这是三个完全不同的概念,做不同的事情。

    扩展方法允许您向已存在的类添加方法。与创建以该类的对象作为参数的方法相比,这可以产生更好的 API。

    构建器模式允许您通过首先在可变对象中设置这些参数,然后调用“构建”方法来初始化您正在创建的(通常是不可变的)对象来构造具有许多选项和参数的对象。这很有用,因为它消除了对带有许多参数的巨大构造函数的需求,并且当其中一些参数是可选的默认值时特别有用。

    流畅的 API 意味着“setter”方法将返回对象本身,而不是返回 Unit/void。这允许一个 API,您可以在其中将方法调用链接在一起。例如使用虚构的 Point2d 类

    val point = new Point2d().setX(3).setY(5)
    

    正在使用流畅的 API

    val point = new Point2d()
    point.setX(3)
    point.setY(5)
    

    没有流畅的 API

    【讨论】:

      最近更新 更多