我编写了以下类和相应的伴随对象:
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()));
答案 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)
就个人而言,我会完全抛弃class
和companion 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
中定义它们。