2014-07-08 56 views
0

我寫了下面的類和相應的同伴對象:斯卡拉工廠模式提高了設計

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? 
    } 
} 

我的問題是,當工廠方法沒有piece它被調用創建一個Tile,什麼是適當的參數傳遞給Tile構造函數?我不想通過null,這似乎是一個糟糕的設計選擇。我是否應該讓主構造參加Option[Piece]並通過None

這似乎有點太醜陋,因爲當我想創建一個瓦我需要說:

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

回答

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))

+0

案例類看起來像最乾淨的方法,謝謝 –

+0

你可以有一個案例類,並添加一個額外的工廠方法嗎? –

+1

@AmirAfghani,是的,你可以。只需爲該類定義一個伴隨對象並向其添加方法即可。不過,這些方法不應該與編譯器生成的方法衝突。 –

2

如果pieceOnTile是可選的,那麼你應該使用Option肯定。如果你不喜歡創造的Tile新實例時包裹Piece S IN Some的醜惡,然後隱藏它內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將顯得更爲階狀:

def isOccupied() : Boolean = pieceOnTile.isDefined 
+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) 
    } 

} 
+0

如果您不習慣使用「map」這種方式,也可以使用模式匹配來編寫toString()方法 – scand1sk

+0

感謝您的回答! –

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),你既可以由0​​標誌或通過模式匹配檢查瓷磚。

這種方法的一個可能的優點是,如果您添加更多方法假定包含的部分,則不必爲每個方法添加佔有率檢查,因爲您可以首先在OccupiedTile中定義它們。

+0

+1我真的很喜歡這種方法 –