Search code examples
scalaapplycode-reuse

Reuse object's apply functions in Scala


I have a class A and factory functions using apply method.

object A {
  def apply(a:String) {... new A}
  def apply(a:Int) {... new A}
  ...
}

class A(...) {
...
}

When I have a subclass B from A with the same factory methods. I have the same apply methods that generates B.

object B {
  def apply(a:String) {... new B} // duplication
  def apply(a:Int) {... new B} // duplication 
  ...
}

class B(...) extends A {
...
}

Can I reuse the apply methods from A in B?


Solution

  • One way to do this is to define a mixin trait that contains the common methods, which will depend on an abstract factory function. Then, the companion objects can extends such mixin, only implementing the specific way to create the corresponding instance.

    An example:

    trait FooFactory[T] {
        def make(s:String, i:Int): T
        def apply(s:String):T = make(s, 0)
        def apply(i:Int):T = make("", i) 
    }
    
    class A(s:String = "", i:Int = 0) {
      def foo:String = s+i
      override def toString() :String = s"[$foo]"
    }
    
    // object A {
    //   def apply(a:String): A = { new A(s=a)}
    //   def apply(a:Int): A = { new A(i=a)}
    // }
    
    object A extends FooFactory[A] {
        def make(s:String, i:Int) = new A(s,i)
    }
    
    class B(s:String = "") extends A(s,-1){
      override def foo:String = s+":"+super.foo
    }
    
    // object B {
    //   def apply(a:String):B = { new B(a)}
    //   def apply(a:Int):B = { new B(a.toString)}
    // }
    
    object B extends FooFactory[B] {
        def make(s:String, i:Int) = new B(s)
    }
    

    If you need access to specific methods of the target class hierarchy, you can constrain the type to that class of its subtypes.

    trait FooFactory[T <: A] {
        def make(s:String, i:Int): T
        def apply(s:String): T = make(s, 0).someAMethod()
    }