scala - 如何在 Scala 中对基于字符串的静态 ID 的枚举进行建模?
问题描述
假设我有一个参考数据表roles
,其中填充了用户可能被授予的所有角色。这些行非常稳定,这意味着很少有人向表中添加新角色。此外还有一个users
table 和一个 join-table users_roles
。实际上,该roles
表只需要通过添加记录来授予用户一些预定义的角色users_roles
。
表roles
很简单:
CREATE TABLE IF NOT EXISTS admin.roles (
id CHAR(16) PRIMARY KEY,
description VARCHAR(256) NOT NULL
);
以下示例描述了一个角色:
INSERT INTO admin.roles VALUES('CS_AGENT', 'A customer service agent');
显然,我需要id
代码中某处的可能值。这是一组字符串,但我想防止魔术字符串并使这种类型更安全。
据我了解,有几种选择:
- 为每个角色 ID 创建一个符号
- 创建一个
RoleId
扩展String
并声明 vals的新类型
为了定义一组角色 ID,我的选项如下:
- 使用
Enumeration
- 使用密封特征/密封对象并从中派生案例对象
我将 JOOQ 用于我的持久层,如果我可以在查询中使用类型安全的 RoleId 而无需手动将其转换为 String ,反之亦然。
什么是最好的解决方案?
解决方案
我不太确定我能解决你所有的问题,但这样的解决方案不好吗?
/** Represents a RoleId from the roles table. */
sealed trait RoleId {
def name: String
def description: String
override final def toString: String = name
}
object RoleId {
case object CS_AGENT extends RoleId {
override val name = "CS_AGENT"
override val description = "A customer service agent"
}
// Define all other roles...
/** All roles */
val allRoles: Set[RoleId] = Set(
CS_AGENT,
// All other roles...
)
/** Returns an RoleId given its name, if the name is not found this will return a None. */
def fromString(name: String): Option[RoleId] = name.toUpperCase match {
case "CS_AGENT" => Some(CS_AGENT)
// All other cases..
case _ => None
}
}
这是完全类型安全的,如果你需要去/从一个字符串有toString
和fromString
方法。
这种方法的唯一(大)缺点是很多样板代码很容易搞砸 - 创建一个新RoleId
但不将其添加到Set
名称或案例中的拼写错误等。
解决此问题的另一种方法是使这个文件由SBT从某种配置中自动生成(如果在构建环境中可以访问,甚至读取 SQL 表),对于那部分,我对另一个问题的这个答案可能会有所帮助。
推荐阅读
- javascript - 如何使用 Debounce Lodash React Native 加快搜索速度
- javascript - 如何获取存储在网站 Firebase 存储中的图像列表?
- java - javax.ws.rs.ProcessingException:找不到内容类型应用程序/x-www-form-urlencoded 类型的编写器:javax.ws.rs.core.Form$1
- android - 如何更改通知图标?
- javascript - Angular 5-如何向构造函数添加多个参数?
- javascript - 为角度控制器脚本创建单独的文件时出现“ReferenceError:未定义角度”
- python-3.x - 如何运行 opencv_traincascade?
- python - 带有尾随'L'的字典转换表单python字符串
- c++ - 使用模板打印出一个类
- python - 如何快速取消嵌套 Pandas 数据框