Scala中带有case类的工厂设计模式

Scala中带有case类的工厂设计模式,scala,companion-object,Scala,Companion Object,我正在尝试使用伴生对象上可用的apply方法在Scala中实现工厂设计模式。我有以下方法 MyType{ def参数:字符串 } case类TypeA(param:String)扩展了MyType case类TypeB(param:String,anotherParam:String)扩展了MyType 对象MyType{ def应用(参数:字符串):类型A=??? def apply(参数,另一个参数:字符串):类型B=??? } 现在,在创建TypeA或TypeB的实例时,如何强制上述tr

我正在尝试使用伴生对象上可用的apply方法在Scala中实现工厂设计模式。我有以下方法

MyType{
def参数:字符串
}
case类TypeA(param:String)扩展了MyType
case类TypeB(param:String,anotherParam:String)扩展了MyType
对象MyType{
def应用(参数:字符串):类型A=???
def apply(参数,另一个参数:字符串):类型B=???
}

现在,在创建
TypeA
TypeB
的实例时,如何强制上述trait的调用方通过同伴对象?

您可以简单地调用case类本身的
apply
方法。似乎没有办法阻止客户端代码调用
TypeA。不过,直接应用
,因为这会阻止
MyType
调用它

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 = TypeA(param)
   def apply(param: String, anotherParam: String): TypeB = TypeB(param, anotherParam)
}

trait
MyType
已密封。其他人可以像
newmytype{}
那样实例化它

然后可以删除案例类

//不再有公共案例类TypeA和TypeB
对象MyType{
def apply(p:String):MyType=/*案例A*/新MyType{val param=p}
私有case类InternalB(param:String,other:String)扩展了MyType
def apply(参数:字符串,另一个参数:字符串):MyType=InternalB(参数,另一个参数)
}
此时,需要使用companion对象来创建
MyType
实例

然后可以恢复这些不同情况下的模式匹配

对象MyType{
//应用函数,以及此后的提取器。。。
/**提取强制参数,不管是什么情况*/
def unapply(t:MyType):选项[String]=Some(t.param)
/**提取两个参数,情况B为额外参数,其他为无*/
def unapply(t:MyType):选项[(字符串,字符串)]=t匹配{
案例B(强制、额外)/*仅可能作为私人案例存在*/=>
部分(强制->额外)
案例=>无
}
}
//那么模式匹配就可以。。。
val test1:Boolean=MyType(“A”)匹配{
案例MyType(参数)=>真
大小写=>false
}
//这将是真的
val test2:Boolean=MyType(“B”,“extraB”)匹配{
案例MyType(参数,额外)=>真
大小写=>false
}
//这将是真的
val test3:Int=MyType(“A”)匹配{
案例MyType(参数,额外)=>2
案例MyType(参数)=>1
大小写=>0
}
//将是1
val test4:Boolean=MyType(“B”,“extraB”)匹配{
案例MyType(参数)=>真
大小写=>false
}
//这将是真的

它允许对实例进行完全控制,并对案例的实现进行抽象。

您可以将案例类移动到伴随对象中,并将构造函数设置为私有的,并且仅在伴随对象中访问

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)
}
除非通过反射,否则没有人能够直接实例化case类

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??")
                     ^
scala>MyType(“测试”)
res0:MyType.TypeA=TypeA(测试)
scala>MyType(“测试”,“另一个测试”)
res1:MyType.TypeB=TypeB(测试,另一个测试)
scala>MyType.TypeA(“测试”)
:12:错误:无法在对象$iw中访问类TypeA中的构造函数TypeA
MyType.TypeA(“测试”)
^

我希望行为为MyType。apply(“testParam”)应返回TypeA。我想要避免的是用户直接调用TypeA(“testParam”)。所以基本上我所看到的是通过在case类本身中传递apply方法。也许我错过了一些东西,完成以下行怎么样:def apply(param:String):TypeA=TypeA(param)def apply(param:String,anotherParam:String):TypeB=TypeB(param,anotherParam)这是我看完一些文章后所做的。无论如何,谢谢你发布这个!