简体   繁体   中英

cake pattern Scala

  import scala.collection.mutable
    
   class Session
    
    trait SessionProvider:
      def session: Session
    
    trait DefaultSessionProvider extends SessionProvider:
      val dummySession = new Session
      override def session = dummySession
    
    abstract class Identity
    
    trait IdentityCache:
      def getOrAuthenticate():Session
    
    
    trait InMemoryIdentityCache extends SessionProvider:
    
      val cache = mutable.Map.empty[Session, SessionProvider]
      override def getOrAuthenticate():InMemoryIdentityCache  =
        cache.getOrElseUpdate(session, authenticate())
    
    trait Authenticator:
    
      def authenticate():Session
    
    trait UsesSAMLIdentity:
    
    
      class SAMLIdentity(val saml: String) extends Identity
    
    trait SAMLAuthenticator extends Authenticator with UsesSAMLIdentity:
      val dummySAMLIdentity = new SAMLIdentity("XXX")
      override def authenticate() = dummySAMLIdentity
    
    
    trait RoleManager:
      def hasRole(role: String): Boolean
    
    
    trait SAMLRoleManager extends RoleManager with UsesSAMLIdentity:
    
      override def hasRole(role: String): Boolean =
        val identity = getOrAuthenticate()
        identity.saml == "XXX"
    
    
    object WebApp extends SAMLRoleManager :
    
      def main(args: Array[String]): Unit =
        println(hasRole("YYY")) // Prints "true"
       

I am new in Scala and I am trying to implement the above code to print true in main. My problem is that my IDE says "Not found: authenticate" and "Not found session" in trait InMemoryIdentityCache. I am a little confused about how to implement this cake pattern.

I will appreciate any help.

InMemoryIdentityCache extends SessionProvider but doesn't implement session . So whatever extends it would have to provide it. From what I see only DefaultSessionProvider has it defined, but nothing mixes it in. Actually nobody mixes-in any SessionProvider as far as I can see).

InMemoryIdentityCache doesn't extend Authenticator so it cannot access authenticate() . If you want to tell compiler that it should extends Authenticator and a method will be there, you need:

trait InMemoryIdentityCache extends ...:
  self: Authenticator =>

The fact that "final" cake might have all the methods doesn't allow you to miss them in the intermediate cake layers.

Also cake pattern is widely recognized as antipattern. Rewrite your code to use constructors to inject dependencies and you'll immediately see where there are issues and why.

import scala.collection.mutable
    
class Session
abstract class Identity
class SAMLIdentity(val saml: String) extends Identity


trait SessionProvider:
  def session: Session

class DefaultSessionProvider extends SessionProvider:
  val dummySession = new Session
  override def session = dummySession


trait Authenticator:
  def authenticate(): Identity // you had Session, it didn't work  

class SAMLAuthenticator extends Authenticator:
  val dummySAMLIdentity = new SAMLIdentity("XXX")
  override def authenticate() = dummySAMLIdentity // because your return SAMLIdentity


trait IdentityCache:
  // you had Session her as well, even though there is Identity in class name
  def getOrAuthenticate(): Identity 

class InMemoryIdentityCache(
  sessionProvider: SessionProvider,
  authenticator: Authenticator
) extends IdentityCache:
  val cache = mutable.Map.empty[Session, Identity] // you had [Session, SessionProvider] ?!?
  override def getOrAuthenticate(): Identity  =
    cache.getOrElseUpdate(sessionProvider.session, authenticator.authenticate())


trait RoleManager:
  def hasRole(role: String): Boolean

class SAMLRoleManager(identityCache: IdentityCache) extends RoleManager:
  override def hasRole(role: String): Boolean = 
    identityCache.getOrAuthenticate() match {
      case identity: SAMLIdentity => identity.saml == "XXX"
      case _ => false
    }


object WebApp:
    
  def main(args: Array[String]): Unit =
    val sessionProvider: SessionProvider = new DefaultSessionProvider
    val authenticator: Authenticator = new SAMLAuthenticator
    val identityCache: IdentityCache = new InMemoryIdentityCache(sessionProvider, authenticator)
    val roleManager: RoleManager = new SAMLRoleManager(identityCache)
    println(roleManager.hasRole("YYY")) // Prints "true"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM