scalaself-typecake-pattern

How to keep single responsibility when using self-type in Scala?


Using self-type for dependency injections, cause to expose public method of other traits ,which break the single responsibility principal. Let's me talk with example

trait Output {
  def output(str: String): Unit
}

trait ConsoleOutput extends Output {
  override def output(str: String): Unit = println(str)
}

class Sample {
  self: Output =>

  def doSomething() = {
    // I do something stupid here!
    output("Output goes here!")
  }
}

val obj = new Sample with ConsoleOutput
obj.output("Hey there")

My Sample class dependes on Output trait and of course I would like to use Output trait methods in my Sample class. But with above code example my Sample class expose output method which doesn't come from its functionality and break single responsibility of Sample.

How can I avoid it and keep using self-type and cake-pattern?


Solution

  • Responsibility of providing the output still lies with the component implementing Output. The fact that your class provides access to it is no different from something like:

      class Foo(val out: Output)
      new Foo(new ConsoleOutput{}).out.output
    

    Sure, you can make out private here, but you could also have .output protected in ConsoleOutput if you don't want it accessible from outside as well.

    (The answer to your comment in the other answer is that if you also want to use it "stand-alone", then you subclass it, and make output public in the subclass).