scala中的商务逻辑错误处理

时间:2017-01-28 11:25:40

标签: scala exception-handling

我正在使用Scala和Play Framework 2.5开发Web服务。我的应用有典型的分层架构。我有以下课程:model.Userrepository.UserRepositoryservice.UserServicecontrollers.UserController我正试图在不使用Exception的情况下处理商务逻辑错误的好方法。

考虑以下情况:收到了注册新用户的请求。请求正文中有两个参数:emailpassword。这些参数被输入UserService#registerUser,检查电子邮件是否有效以及是否已存在此类电子邮件的用户。我的解决方案是使UserService#registerUser返回Either[BuisnessFailure, Int]个对象。 BuisnessFailure是一种特质,由WrongEmailFormatFailureUserAlreadyExistFailure继承。 如果电子邮件无效,则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)

UserRepository:

package repository

import model.User

class UserRepository {
  def create(user: User): Int = ???
  def find(email: String): Option[User] = ???
}

UserService:

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 = ???
}

UserController中:

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
    }
  }
}

BuisnessFailure:

package util

sealed trait BuisnessFailure
case object UserAlreadyExistFailure extends BuisnessFailure
case object WrongEmailFormatFailure extends BuisnessFailure

1 个答案:

答案 0 :(得分:4)

这正是我们针对一个最大项目的错误处理所做的,我们没有遇到任何问题。 Either应该像这样使用。错误Left,结果Right

  • 它的类型安全
  • 无需担心并发性
  • 代码可扩展且可维护

唯一的一点是,由于大多数Scala应用程序都是非阻止(异步),因此人们会使用Future[Either[Error, Int]]而不是Either[Error, Int]。但是,它仍然没关系,因为每当你决定采用非阻塞时,你可以轻松地将Either包裹在Future内,正如我告诉你的那样,不用担心并发问题。