The difference between using the Cake template and functions in Scala - why is the Cake template useful?

I was interested to learn about the difference between using functions and Cake's DI pattern in Scala. I came up with the following understanding (s), I would like to know if this understanding is correct.

Imagine a dependency graph.

1) If we use functions as building blocks, then the graph consists of functions as nodes and parameters as edges.

2) If we use traits as building blocks (as in Cake), then the graph consists of traits as nodes and abstract members as edges.

So what is the purpose of the Cake pattern? Why is 2 better than 1? Of course. Graph-1 can be simplified by grouping functions into features, and then we have a smaller, more understandable graph-2. Grouping / clustering related concepts is a form of compression and creates understanding (we need to keep fewer things in our head in order to understand).

Here is another comparison (between Cake vs package system):

Cake is like grouping related functions into packages, but it goes beyond that because using namespaces (packages / objects) leads to tight dependency relationships, Cake replaces packages / objects with traits and importits own type of annotation / abstract members. The difference between packages and the Cake template is that the actual dependency implementation can change using Cake, while it cannot change when using packages.

I don’t know if these analogies make sense or not, if you don’t correct me, if so, please calm me down. I'm still trying to wrap my head around the Cake pattern and how to relate it to concepts that I already understand (functions, packages).

+4
1

(DI) / ( ) / . / :

trait Logger { 
  // fancy logging stuff 
}

class NeedsALogger {
  private var l: Logger = _
  def logger: Logger = l
  def logger_=(newLogger: Logger) {
    l = newLogger
  }
  // uses a Logger here
}

getter/setter. , - . DI, , - , DI . , , , ( ):

class NeedsALogger(logger: Logger) {
  // uses a Logger here
}

, Cake? -, Cake:

class NeedsALogger {
  logger: Logger => 
  // Uses a Logger here
}

logger: Logger =>. self-type, Logger Logger. NeedsALogger Logger, . NeedsALogger Logger, , . , NeedsALogger Logger. :

trait FooLogger extends Logger {
  // full implementation of Logger
}

trait BarLogger extends Logger {
  // full implementation of Logger
}

val a = new NeedsALogger with FooLogger
val b = new NeedsALogger with BarLogger
val c = new NeedsALogger // compile-time error! 

, . DI , , . , , .

Cake , . , .

+2

Source: https://habr.com/ru/post/1665087/


All Articles