【发布时间】:2017-01-28 19:51:18
【问题描述】:
我正在使用 Scala 和 Play Framework 2.5 开发 Web 服务。我的应用程序具有典型的分层架构。我有以下课程:model.User、repository.UserRepository、service.UserService 和controllers.UserController,我正在尝试一种不使用Exception 来处理业务逻辑错误的好方法。
考虑以下情况:收到新用户的注册请求。请求正文中有两个参数:email 和password。这些参数被提供给UserService#registerUser,它会检查电子邮件是否有效,以及拥有此类电子邮件的用户是否已经存在。我的解决方案是让UserService#registerUser 作为结果返回一个Either[BuisnessFailure, Int] 对象。 BuisnessFailure 是一个特征,由WrongEmailFormatFailure 和UserAlreadyExistFailure 继承。
如果电子邮件无效,UserService#registerUser 将返回 Left(WrongEmailFormatFailure)。如果已存在具有此类电子邮件的用户,则UserService#registerUser 返回Left(UserAlreadyExistFailure)。如果成功,UserService#registerUser 返回Right(userRepository.create(User(email, password))。之后,在controllers.UserController 中,我可以使用模式匹配来处理这种情况并发送适当的响应。
那么,这种方法是否足以处理类似情况?请在下面找到我的代码:
用户:
package model
case class User(email: String, password: String)
用户存储库:
package repository
import model.User
class UserRepository {
def create(user: User): Int = ???
def find(email: String): Option[User] = ???
}
用户服务:
package service
import model.User
import repository.UserRepository
import util.{BuisnessFailure, UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserService {
private val userRepository: UserRepository = ???
def registerUser(email: String, password: String): Either[BuisnessFailure, Int] = {
if (userAlreadyExists(email))
Left(UserAlreadyExistFailure)
else
if (!isEmailValid(email))
Left(WrongEmailFormatFailure)
else
Right(userRepository.create(User(email, password)))
}
private def isEmailValid(email: String): Boolean = ???
private def userAlreadyExists(email: String): Boolean = ???
}
用户控制器:
package controller
import service.UserService
import util.{UserAlreadyExistFailure, WrongEmailFormatFailure}
class UserController extends play.api.Controller {
private val userService = new UserService
def signUp() = Action(parse.json) { implicit request =>
//obtaining email and password parameters from request body
val email = ???
val password = ???
userService.registerUser(email, password) match {
case Left(WrongEmailFormatFailure) => // send 400 code and appropriate error message
case Left(UserAlreadyExistFailure) => // send 400 code and appropriate error message
case Right(_) => // send response with 200 code
}
}
}
商业失败:
package util
sealed trait BuisnessFailure
case object UserAlreadyExistFailure extends BuisnessFailure
case object WrongEmailFormatFailure extends BuisnessFailure
【问题讨论】:
-
@Jubobs 感谢您的链接。我从未听说过 softwareengineering.stackexchange.com。
-
我会将验证作为另一种服务,因此它更具可测试性和可重用性
-
@Jubobs 在引用其他网站时,指出cross-posting is frowned upon 通常会有所帮助
-
@gnat 我不是在建议交叉发布,而是从 SO 中删除问题并将其发布在软件工程上。