扩展方法、构建器模式和流畅的界面之间有什么区别?
What is the difference between an extension method, the builder pattern and the fluent interface?
在 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 提供了相似的接口。
我的问题是:扩展方法、构建器模式和流畅接口之间有什么区别?
这是三个完全独立的概念,做不同的事情。
扩展方法允许您向已存在的 class 添加方法。这比创建一个将 class 的对象作为参数的方法更好 API。
构建器模式允许您构造具有许多选项和参数的对象,方法是首先在可变对象中设置这些参数,然后调用 "build" 方法来初始化您正在创建的(通常是不可变的)对象。这很有用,因为它消除了对具有许多参数的巨大构造函数的需要,并且当其中一些参数是默认值可选时特别有用。
流利的 API 意味着 "setter" 方法将 return 对象本身而不是 returning Unit/void。这允许 API 您可以在其中将方法调用链接在一起。例如使用虚构的 Point2d class
val point = new Point2d().setX(3).setY(5)
正在使用流利的API
val point = new Point2d()
point.setX(3)
point.setY(5)
不流利API
在 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 提供了相似的接口。
我的问题是:扩展方法、构建器模式和流畅接口之间有什么区别?
这是三个完全独立的概念,做不同的事情。
扩展方法允许您向已存在的 class 添加方法。这比创建一个将 class 的对象作为参数的方法更好 API。
构建器模式允许您构造具有许多选项和参数的对象,方法是首先在可变对象中设置这些参数,然后调用 "build" 方法来初始化您正在创建的(通常是不可变的)对象。这很有用,因为它消除了对具有许多参数的巨大构造函数的需要,并且当其中一些参数是默认值可选时特别有用。
流利的 API 意味着 "setter" 方法将 return 对象本身而不是 returning Unit/void。这允许 API 您可以在其中将方法调用链接在一起。例如使用虚构的 Point2d class
val point = new Point2d().setX(3).setY(5)
正在使用流利的API
val point = new Point2d()
point.setX(3)
point.setY(5)
不流利API