Scala工厂模式改进设计

时间:2014-07-08 22:17:41

标签: scala factory

我编写了以下类和相应的伴随对象:

class Tile(val tileCoordinate: Int, val pieceOnTile: Piece) {
    override def toString(): String = {
        if(isOccupied()) {
            pieceOnTile.toString()
        }
        "-"
    }

    def isOccupied(): Boolean = pieceOnTile != null
}

object Tile {
    def apply(coordinate: Int, piece: Piece): Tile = {
        new Tile(coordinate, piece)
    }

    def apply(coordinate: Int): Tile = {
        new Tile(coordinate, ??) // what is the best design here?An Option?
    }
}

我的问题是,当调用创建Tile而没有piece的工厂方法时,传递给Tile构造函数的适当参数是什么?我不想传递null,这似乎是一个糟糕的设计选择。我应该让主构造函数采用Option[Piece]并传递None吗?

这看起来有点难看,因为当我想创建一个瓷砖时,我需要说:

val t = Tile(1, Some(new Knight()));

4 个答案:

答案 0 :(得分:3)

我会编写以下代码:

class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) {

  // A little bit more scala-idiomatic, and a probable bug corrected
  override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")

  def isOccupied : Boolean = pieceOnTile.isDefined

}

object Tile {

  def apply(coordinate: Int, piece: Piece): Tile = {
    new Tile(coordinate, Some(piece))
  }
  def apply(coordinate: Int): Tile = {
    new Tile(coordinate, None)
  }

}

答案 1 :(得分:3)

就个人而言,我会完全抛弃classcompanion object,而是选择case class

case class Tile(tileCoordinate: Int, pieceOnTile: Option[Piece] = None) {
  override def toString(): String = pieceOnTile.map(_.toString).getOrElse("-")
}

这使您可以在检查值时稍后执行以下操作:

... match {
  case Tile(c, Some(p)) => ...
  case Tile(c, None) => ...
}

将第二个参数默认设为None,您可以将其称为Tile(coord)Tile(coord, None)Tile(coord, Some(piece))

答案 2 :(得分:2)

如果pieceOnTile是可选的,那么您应该使用Option。如果您不喜欢在创建Piece的新实例时必须在Some中包裹Tile的丑陋,请将其隐藏在apply中:

class Tile(val tileCoordinate: Int, val pieceOnTile: Option[Piece]) { ... }

object Tile {

  def apply(coordinate: Int, piece: Piece): Tile = new Tile(coordinate, Some(piece))

  def apply(coordinate: Int): Tile = new Tile(coordinate, None)
}

然后即使isOccupied看起来更像scala:

 def isOccupied() : Boolean = pieceOnTile.isDefined

答案 3 :(得分:2)

另一种选择可能是将空/被占用的案例定义为单独的案例类:

sealed abstract class Tile(val isOccupied: Boolean)

case object EmptyTile extends Tile(false) {
  override def toString: String = "-"
}

case class OccupiedTile(piece: Piece) extends Tile(true) {
  override def toString: String = piece.toString
}

您可以使用EmptyTile,创建OccupiedTile(piece),然后您可以通过isOccupied标记或模式匹配来检查平铺。

这种方法的一个可能的优点是,如果添加更多假定包含片段的方法,则不必为每个方法添加占用率检查,因为您只能在OccupiedTile中定义它们。