【问题标题】:Buisness logic error handling in scalascala中的业务逻辑错误处理
【发布时间】:2017-01-28 19:51:18
【问题描述】:

我正在使用 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)

用户存储库:

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

【问题讨论】:

  • 好问题,但更适合softwareengineering.stackexchange.com
  • @Jubobs 感谢您的链接。我从未听说过 softwareengineering.stackexchange.com。
  • 我会将验证作为另一种服务,因此它更具可测试性和可重用性
  • @Jubobs 在引用其他网站时,指出cross-posting is frowned upon 通常会有所帮助
  • @gnat 我不是在建议交叉发布,而是从 SO 中删除问题并将其发布在软件工程上。

标签: scala exception-handling


【解决方案1】:

这正是我们在最大项目之一的错误处理方面所做的,我们没有遇到任何问题。 Either 应该完全像那样使用。 Left 表示错误,Right 表示结果。

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

唯一的一点是,由于大多数 Scala 应用程序都是非阻塞(异步)的,人们会使用 Future[Either[Error, Int]] 而不是 Either[Error, Int]。不过,这没关系,因为每当您决定使用非阻塞时,您都可以轻松地将 Either 包装在 Future 中,正如我告诉您的,不用担心并发问题。

【讨论】:

    猜你喜欢
    • 2012-11-15
    • 2015-04-20
    • 2011-02-07
    • 1970-01-01
    • 2018-12-09
    • 2016-11-14
    • 2010-12-03
    • 1970-01-01
    • 2012-05-04
    相关资源
    最近更新 更多