如何应对所谓的“流利”#34;或者"建设者"接口

时间:2016-07-17 20:34:02

标签: scala

当你在编译时知道配置时它们很好,但是当你需要根据某些运行时条件构建一个对象时,它看起来很奇怪。

val req = Request()

val secureReq = if (needSecurity) req.withSecurity else req
val throttledReq = if (needThrottling) secureReq.withThrottling else secureReq
val pooledReq = if (needPooling) throttledReq.withPooling else throttledReq

// etc etc ad infinitum

也许在Scala中编写这种代码有更好,更简洁的方法吗?

2 个答案:

答案 0 :(得分:3)

Scala暗示救援。

    object PimpedBuilders {
        implicit class Pimped[T](val builder: T) extends AnyVal {
          def unless(what: Boolean)(then: T => T): T = 
             if(what) builder else then(builder)
       }
   }

  import PimpedBuilders._
  req
     .unless(!needSecurity){ _.withSecurity}  
     .unless(!needThrottling} { _.withThrottling }
    .unless(!needPooling) { _.wothPooling }

答案 1 :(得分:1)

这个解决方案有点复杂,但应该避免重复自己。

请注意,我无法检查REPL上的代码,但它应该会给你一个想法。

/************************************************
 * This part is used once
 ************************************************/
//We define a request-transforming type
type Configuration = Request => Request

/* now we prepare configuration selectively based on a flag
 * the function is curried to store different configurations
 * once, leaving the flag to be defined only as we actually
 * prepare the request.
 * Note that a false flag will give back the identity function
 * from Predef that leaves the argument untouched
 */
def configuring(conf: Configuration)(flag: boolean) = 
  if (flag) conf else identity

//The available configuration types, wrapping the "fluent" calls
val secured_?: Boolean => Configuration = configuring(_.withSecurity)
val throttled_? = configuring(_.withThrottling)
val pooled_? = configuring(_.withPooling)

/************************************************
 * This part is used each time we need 
 * to configure a request
 ************************************************/
val req = Request()

/* prepare a sequence of configurations
 * and compose them sequentially
 */
def configurations: Configuration = Seq(
  secured_?(needSecurity),
  throttled_?(needThrottling),
  pooled_?(needPooling)
).reduce(_.compose(_))

/* apply the combined configuring 
 * function to the new request
 */
val configured = configurations(req)