2016-07-17 1 views
1

컴파일 타임에 구성을 알았을 때 유용하지만 런타임 조건에 따라 객체를 작성해야 할 때 이상하게 보입니다."유동성"또는 "빌더"인터페이스를 다루는 방법

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 

이런 종류의 코드를 스칼라에 작성하는 것이 더 좋을까요?

+3

매개 변수로 플래그를 취할 것입니다 더 나은 인터페이스 것 같아 그래서 당신 수 만 할'req.withSecurity (needSecurity) .withThrottling (needThrottling) .withPooling (needPooling)'. – michaelsnowden

+0

저는 외부 라이브러리에 대해 대부분 염려하고 있습니다 – synapse

+0

네가 나쁜 제 3 자 디자인을 바꿀 수 없다는 것은 유감입니다. – michaelsnowden

답변

3

스칼라가 구조에 함축합니다.

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 } 

+0

+1, 왜 (더블) 부정을 소개 했습니까? – Bergi

+0

@Bergi, 그저 환상의 행운입니다 :) 나는이 메소드를'if'라고 부를 수는 없으며, 순간적으로 멋지고 간결하게 들릴 대안을 생각할 수 없습니다. 'doIf'는 그냥 서투른 것처럼 들렸습니다 ../ – Dima

+0

'wrapIf' 어쩌면? – Bergi

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)