我目前正在我的控制器中使用来自客户端A
的API。客户A
的示例定义:
class A @Inject()(
ws: WSClient)
{
def createSession(request: CreateSessionRequest)
: EitherT[Future, AppError, ResponseFromA] =
{
//logic. Returns ResponseFromA case class
}
}
我的控制器代码是:
class MyController @Inject()(
a: A) {
def createSession(): Action[JsValue] =
action.async(parse.tolerantJson) { request =>
val requestValidation = for {
request <- EitherT.fromEither[Future](
checkRequest[CreateCheckout](request.body.toString, mapper))
} yield {
request
}
val createSessionResult = for {
createCheckoutInput <- requestValidation
createSessionResponse <- a.createSession(
CreateSessionRequest(createCheckoutInput))
} yield {
createSessionResponse
}
// postProcessing creates a transfer object `SessionResult`
// from `ResponseFromA`
postProcessing(createSessionResult)
}
现在我计划迁移到另一组API,它提供类似的功能但响应格式不同。我创建了一个不同的客户端B
,如下所示:
class B @Inject()(
ws: WSClient)
{
def createSession(request: CreateSessionRequest)
: EitherT[Future, AppError, ResponseFromB] =
{
//logic. Returns ResponseFromB case class
}
}
注意我还在客户端CreateSessionRequest
中使用了B
。这是因为两组API的输入是相同的。我想A/B
测试两组API。理想情况下,我想使用相同的控制器,因为如果我为客户端B
创建了另一个控制器,则控制器有很多逻辑需要复制。来自我的控制器的响应仍然是SessionResult
,因为我希望这些迁移更改对使用我的服务的所有客户端都是透明的。
我正在查看不同的设计模式,例如factory pattern,根据某些规则(比如说使用客户端B
的配置值)有条件地选择正确的客户端,但我到达了死胡同,因为来自两个客户的createSession
具有不同的返回值。我还在考虑创建一个可以用来按摩ResponseFromA
和ResponseFromB
的常用业务对象
postProcessing(createSessionResult)
到公共业务对象,但这意味着我需要更改@Controller
public class ShowFormController {
@RequestMapping(value = "/showForm", method = RequestMethod.GET)
public String showForm(Model model) {
model.addAttribute("message", new Message());
return "show";
}
}
。
任何有关如何在不更改控制器逻辑的情况下有条件地使用我选择的客户端的提示或指示将非常感激。
答案 0 :(得分:0)
如果您想在两种情况下重复使用Controller,您可以:
For Creation:使用工厂,例如注入两个服务,然后返回已配置的服务。
对于返回类型:在这里您需要一个通用格式,我有时会在这里使用play.api.libs.json.JsValue
。
如果您可以重复使用postProcessing
取决于ResponseFromA
和ResponseFromB