use*_*116 7 functional-programming scala
正如标题中所提到的,使用这种数据结构是否有意义?让我逐一解释:
看着这个我有点害怕.使用这种类型的组合是一个好习惯吗?
我们来看一下解决方案空间:
Success(Right(Some(user))) => Everythig OK, got an user
Success(Right(None)) => Everything OK, no user
Success(Left(AppError)) => Something went wrong at app level
Failure(Exception) => Something went wrong
Run Code Online (Sandbox Code Playgroud)
这看起来非常具有表现力,但是当你尝试用其他调用组合这样的嵌套结构时(参见转换阻塞代码到使用scala期货)作为一个组合的例子,事情变得很难看Future[Option[T]]
)
因此,遵循最小权力的原则,我们会问自己:是否存在保留语义的不太复杂的替代方案?有人可能会说,Future[User]
如果我们充分利用异常(和异常层次结构)的潜力,那就足够了.
让我们检查:
Everythig OK, got an user => Success(user)
Everything OK, no user => Failure(UserNotFoundException) (Application level exception)
Something went wrong at app level => Failure(AppException) (Application level exception)
Something went wrong => Failure(Exception) (System-level exception)
Run Code Online (Sandbox Code Playgroud)
此方法的唯一限制是API的用户需要了解异常,这在界面中不会自我记录.最重要的是,拥有基于Future
s 的API 将允许具有其他Future
基于API的表达性monadic组合.
像Future[Either[AppError, Option[User]]]
返回类型这样的事情在原型设计时可能没问题,但是一旦完成原型设计,您应该考虑提供更好的可读性和可表达性的选项。
让我们以此Future[Either[AppError, Option[User]]]
为例。假设有一个方法具有此返回类型。
def fetchUser(userId: UUID): Future[Either[AppError, Option[User]]]\n
Run Code Online (Sandbox Code Playgroud)\n\n现在,您可以选择创建更具表现力的类型层次结构......例如,
\n\n// Disclamer :\n// this is just for pointing you out towards a direction and\n// I am sure many can propose a better design hierarchy\n\ntrait Model\ncase class User(id: UUID,....) extends Model\n\n// Fetch Result protocol\n\nsealed trait FetchModelResult\n\ncase class FetchModelSuccess(model: Model) extends FetchModelResult\n\nsealed trait FetchModelFailure extends FetchModelResult\n\ncase class ModelNotFound extends FetchModelFailure\n...\ncase class FetchModelGenericFailure(ex: Exception) extends FetchModelFailure\n\n// App Result protocol\n\nsealed trait AppResult\n\ncase class AppResultSuccess[T](result: T) extends AppResult\n\nsealed trait AppResultFailure extends AppResult\n\ncase class AppResultGenericFailure(ex: Exception) extends AppResultFailure\n\n// fetch user problem\n\ndef fetchUser(userId: UUID): Future[FetchModelResult] = ???\n\n// Notice that we are not using the generic AppError here\n// This is called segregation of problems\n// the current problem is fetching the user\n// so our design is just to represent what can happen while fetching\n// Now whichever method is using this can come-up with an AppError\n// or AppResult based on what is gets from here.\n\ndef fetchUserApiHandler(userId: UUID): Future[AppResult] =\n fetchUser(userId).map({\n case FetchModelSuccess(model) => .....\n case FetchModelFailure(ex) => ....\n }) \n
Run Code Online (Sandbox Code Playgroud)\n\n另一种选择是使用 或 的一元组合和转换实用scalaz
程序cats
。
Ra\xc3\xbal Raja Mart\xc3\xadnez 在他的一次演讲中解决了类似的问题,并提出了一些解决这些问题的方法 -团队对 Scala FP 新兴模式的旅程 - Run Wild Run Free
\n