I'm trying to implement a factory design pattern in Scala using the apply methods available on the companion object. I have the following approach.
sealed trait MyType {
def param: String
}
case class TypeA(param: String) extends MyType
case class TypeB(param: String, anotherParam: String) extends MyType
object MyType {
def apply(param: String): TypeA = ???
def apply(param, anotherParam: String): TypeB = ???
}
How do I now force the callers of the above trait to go via the companion object when creating instances of TypeA
or TypeB
?
You can move the case classes inside the companion object, and set the constructors to be private and accessed only within the companion object.
sealed trait MyType {
def param: String
}
object MyType {
case class TypeA private[MyType] (param: String) extends MyType
case class TypeB private[MyType] (param: String, anotherParam: String) extends MyType
def apply(param: String): TypeA = TypeA(param)
def apply(param: String, anotherParam: String): TypeB = TypeB(param, anotherParam)
}
No one would be able to instantiate the case classes directly, unless though reflection.
scala> MyType("Test")
res0: MyType.TypeA = TypeA(Test)
scala> MyType("Test", "another test")
res1: MyType.TypeB = TypeB(Test,another test)
scala> MyType.TypeA("test??")
<console>:12: error: constructor TypeA in class TypeA cannot be accessed in object $iw
MyType.TypeA("test??")
^