首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >能不能改进这个设计(图案).怎么叫呢?

能不能改进这个设计(图案).怎么叫呢?
EN

Stack Overflow用户
提问于 2016-12-16 20:24:16
回答 1查看 235关注 0票数 0

我使用的是Play精巧版本2.5.x和3.1.x。我使用Slick的代码生成器,并从现有的数据库中生成光滑模型。事实上,我不好意思承认我是数据库设计驱动的,而不是类设计驱动的。

这是最初的设置:

  • generated.Tables._环境下生成的光滑模型
  • 通用Slick实现
  • 构建在通用光滑道之上的服务层。

这些是我临时称为“可插拔服务”的模式背后的力量,因为它允许将服务层功能插入到模型中:

  • Play的控制器和视图必须只看到服务层(而不是Dao层),例如UserService
  • 生成的模型(如UserRow )应该符合业务层接口,例如Deadbolt-2的主题,但不能直接实现它。为了能够实现它,我们需要“太多”,例如UserRow模型类型、UserDao以及潜在的一些业务上下文。
  • 一些UserService方法自然适用于模型UserRow实例,例如loggedUser.rolesloggedUser.changePassword

因此,我有:

generated.Tables.scala光滑模型类:

代码语言:javascript
复制
case class UserRow(id: Long, username: String, firstName: String, 
                   lastName : String, ...) extends EntityAutoInc[Long, UserRow]

特定于用户模型的dao.UserDao.scala Dao扩展和自定义:

代码语言:javascript
复制
@Singleton
class UserDao @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)
    extends GenericDaoAutoIncImpl[User, UserRow, Long] (dbConfigProvider, User) {
  //------------------------------------------------------------------------
  def roles(user: UserRow) : Future[Seq[Role]] = {
    val action = (for {
      role <- SecurityRole
      userRole <- UserSecurityRole if role.id === userRole.securityRoleId
      user <- User if userRole.userId === user.id
    } yield role).result

    db.run(action)
  }
}

将所有用户操作都公开到Play应用程序的其余部分的services.UserService.scala服务:

代码语言:javascript
复制
@Singleton
class UserService @Inject()(auth : PlayAuthenticate, userDao: UserDao) {
  // implicitly executes a DBIO and waits indefinitely for 
  // the Future to complete
  import utils.DbExecutionUtils._
  //------------------------------------------------------------------------
  // Deadbolt-2 Subject implementation expects a List[Role] type 
  def roles(user: UserRow) : List[Role] = {
    val roles = userDao.roles(user)
    roles.toList
  }
}

services.PluggableUserService.scala最后是实际的“可插入”模式,该模式动态地将服务实现附加到模型类型:

代码语言:javascript
复制
trait PluggableUserService extends be.objectify.deadbolt.scala.models.Subject {
  override def roles: List[Role]
}

object PluggableUserService {
  implicit class toPluggable(user: UserRow)(implicit userService: UserService) 
    extends PluggableUserService {
    //------------------------------------------------------------------------
    override def roles: List[Role] = {
      userService.roles(user)
    }
}

最后,在控制器中可以这样做:

代码语言:javascript
复制
@Singleton
class Application @Inject() (implicit
                             val messagesApi: MessagesApi,
                             session: Session,
                             deadbolt: DeadboltActions,
                             userService: UserService) extends Controller with I18nSupport {
  import services.PluggableUserService._                           

  def index = deadbolt.WithAuthRequest()() { implicit request =>
    Future {
      val user: UserRow = userService.findUserInSession(session)
      // auto-magically plugs the service to the model
      val roles = user.roles 
      // ...
      Ok(views.html.index)
    }
  }                                

有什么Scala方法可以帮助避免在可插拔的Service对象中编写样板代码吗?可插拔的服务名称有意义吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-16 23:36:05

常见的变体之一可能是控制器的父特征,它具有以下内容:

代码语言:javascript
复制
def MyAction[A](bodyParser: BodyParser[A] = parse.anyContent)
               (block: (UserWithRoles) => (AuthenticatedRequest[A]) => Future[Result]): Action[A] = {
    deadbolt.WithAuthRequest()(bodyParser) { request =>
    val user: UserRow = userService.findUserInSession(session)
    // this may be as you had it originally
    // but I don't see a reason not to 
    // simply pull it explicitly from db or 
    // to have it in the session together with roles in the first place (as below UserWithRoles class)
    val roles = user.roles 

    block(UserWithRoles(user, roles))(request)
}  

房间里的大象就是这样得到userService实例的。那么,您需要在控制器构造函数中显式地要求它(就像使用DeadboltActions一样)。或者,您可以将DeadboltActionsUserService和其他什么捆绑到一个类中(例如ControllerContext?)并将这个单个实例注入为一个构造函数参数(但这可能是另一个讨论.)。

在此之后,控制器代码将如下所示:

代码语言:javascript
复制
def index = MyAction() { implicit user => implicit request =>
    Future {
      // ...
      Ok(views.html.index)
    }
  } 

userrequest都是隐式的,这有助于将其传递到应用程序的内部部分(这通常是这样的--您可以使用user对象来执行某些业务逻辑)。

它并不能摆脱PluggableUserService本身(逻辑仍然存在),但它可以帮助您更容易地在控制器中的任何地方重用相同的逻辑(就像我的经验一样,在任何实际应用程序中,都需要同时使用UserRoles )。

编辑:我有种感觉,我不太明白你的问题。您想要避免PluggableUserService中的样板,还是要避免在每个控制器中使用PluggableUserService来分散这种转换(IMHO第二个选项是要避免的)?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41191944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档