Inheritance and code reuse in stackable traits

前端 未结 3 774
你的背包
你的背包 2020-12-11 18:48

In this simplified experiment, I want to be able to quickly build a class with stackable traits that can report on what traits were used to build it. This reminds me strong

3条回答
  •  我在风中等你
    2020-12-11 19:49

    Here is an example of preferring composition. The amplification logic is refactored.

    I find I must use abstract override once or twice a year or else that brain cell will die.

    In this example, the animal becomes noisier as you mix in more Noise.

    It uses runtime reflection, but of course you could imagine a macro doing something similar. (You'd have to tell it what this is.)

    Real code would of course perform more interesting transforms; for instance, a pig noise mixed in after a duck noise would sound like a goose just delivering an egg.

    package sounds
    
    trait Sound {
      def sound: String
    }
    
    trait Silent extends Sound {
      def sound: String = ""
    }
    
    // duck is always funnier
    trait Duck extends Silent
    
    object Amplifier {
      import reflect.runtime.currentMirror
      import reflect.runtime.universe._
      def apply[A <: Sound : TypeTag](x: Any): Int = {
        val im = currentMirror reflect x
        val tpe = im.symbol.typeSignature
        var i = -1
        for (s <- tpe.baseClasses) {
          if (s.asClass.toType =:= typeOf[A]) i = 0
          else if (s.asClass.toType <:< typeOf[Noise]) i += 1
        }
        i
      }
    }
    
    trait Noise
    trait NoisyQuack extends Sound with Noise {
      abstract override def sound: String = super.sound + noise * amplification
      private val noise = "quack"
      private def amplification: Int = Amplifier[NoisyQuack](this)
    }
    trait NoisyGrunt extends Sound with Noise {
      abstract override def sound: String = super.sound + noise * amplification
      private val noise = "grunt"
      private def amplification: Int = Amplifier[NoisyGrunt](this)
    }
    
    object Test extends App {
      val griffin = new Duck with NoisyQuack with NoisyGrunt {
        override def toString = "Griffin"
      }
      Console println s"The $griffin goes ${griffin.sound}"
    }
    

提交回复
热议问题