基于案例对象的参数

时间:2014-05-15 15:17:02

标签: java scala playframework

我正在从一个非常硬编码的Java实现转变为一个非常模块化的Scala实现,而且我已经无法翻译我的应用程序的一部分。

我正在查看的函数会从格式字符串中生成一条消息。它在数据库中查找相关信息并使用它来格式化字符串。

public static String getHumanizedMessage(Type type, User user, Long relatedId){
    switch(type.getTypeName()){
    case NEW_FOO:{
        Foo foo = Foo.findById(relatedId);
        return String.format(type.getMessage(), user.name, foo.name);
    }
    case BAR_SHARED:{
        Bar bar = Bar.findById(relatedId);
        Baz baz = Baz.findById(relatedId);
        return String.format(type.getMessage(), user.name, bar.name, baz.name);
    }
    default:
        break;
    }
    return null;
}

因此,在Scala方面,我尝试使用案例对象来实现不同类型,这些案例对象都从基础Type扩展。

sealed class Type(val name: String)

case object NewFoo extends Type("New Foo")
case object BarShared extends Type("Bar Shared")

问题是,由于我的应用程序是模块化的,我的MessageService我无法访问Foo.findByIdBar.findByIdBaz.findById。我希望在参数列表中接收相应的字符串,但正如您所看到的,参数的数量因Type而异。我可以使参数可选,但是任何调用该函数的人都需要根据类型知道哪些参数是必需的,我不喜欢这样。我想我可以为每种类型设置不同的功能名称,但我不愿意,如果有更好的方法。

3 个答案:

答案 0 :(得分:1)

我认为您可能需要编码格式化Type的知识。如果您的目标是保持MessageService不可知的任何数据,您可以例如要求每种类型格式化自己,例如:

trait MessageType {
  val name: String
  def format(relatedId: Long): String
}

case class FooMessageType(foo: Foo) extends MessageType {
  val name = "Foo"
  def format(relatedIid: Long) = {
    val foo = Foo.findById(relatedId)
    "This is ${foo.name}"
  }
}

然后您的MessageService只知道MessageType接口,并且将在不同的模块中提供其实现。请注意,您可能需要允许每个模块在启动时针对MessageService注册其MessageType。

答案 1 :(得分:1)

对我而言,这getHumanizedMessage()是一种单一的方法,这似乎很奇怪。由于你的switch语句,你在一个函数中做了两件完全不同的事情。你为什么不把它们分开?

你可以写:

def getHumanizedMessage(foo: Foo, user: User) = String.format(NewFoo.getMessage(), user.name, foo.name)
def getHumanizedMessage(bar: Bar, baz: Baz, user: User) = String.format(BarShared.getMessage(), bar.name, baz.name, user.name)

答案 2 :(得分:0)

你仍然可以使用sealed实现来获得一个简单的匹配语句,你只需要一个抽象类作为基础。

sealed abstract class MessageType {
  val name: String
  def findById[A](relatedId: Long): A
}

然后,您可以根据用例扩展案例对象或案例类:

case object NewFoo extends MessageType {
  val name: String = "NewFoo"
  def findById(relatedId: Long): NewFoo = {...}
}

或者如果你想提供参数:

case class BarShared(defaultName: String) extends MessageType {
  val name: String = defaultName
  def findById(relatedId: Long) BarShared = {...}
}

对于密封类,您的匹配语句不需要默认值,除非您将其定义为扩展名。