如何在 Scala 中表示内部单例
How to denote an inner singleton in Scala
为了锻炼我在 Scala 特定功能上的 OOP 能力,我尝试设计一个游戏,其中我有 Player
class。它有一个抽象方法 play
,它决定给定玩家列表(不同于调用该方法的玩家)采取什么行动。我想阻止 play
方法改变其他玩家的状态。正确的玩法是施放Spell
,让系统将其效果反映到其他玩家身上。
然而,play
方法需要其他玩家的读取权限来决定策略。因此,我创建了一个内部单例 ReadOnlyPlayer
。我将其设为单例以防止一遍又一遍地复制,并且每次都简单地 returning 这个单例。
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[/*?*/]) // how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[/*?*/]) = ()
}
}
由于我添加评论的行,我无法编译它。我知道有许多解决此问题的方法:
如果它是 class 而不是单例,我可以使用 Player#ReadOnlyPlayer
。我试过了,效果很好。但是,这需要每次都创建一个新副本,所以如果我想这样做,实际上创建一个单独的不可变 class 会更好。
我可以手动实现单例模式,并且总是 return 此 class 的相同实例。
我可以将 class 设为私有并且只声明 Player
,但我希望我的客户知道他们明确知道他们将无法修改 Player
实例。我可以使用具有有意义名称的密封空特征来做到这一点。
我知道如何以各种方式处理这个问题,所以我的问题更多是出于好奇:如何表示内部单例类型?
请注意,我在回答时并没有完全理解您要做什么来制作内部单例列表。
通常使用SingletonName.type
访问单例类型。所以,在你的情况下,它看起来像这样:
abstract class Player(private var _health: Int = 0) {
def health = _health
def play(players: List[ReadOnlyPlayer.type]) = ()// how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = Math.max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[ReadOnlyPlayer.type]) = ()
}
}
正如@lloydme 指出的那样,我试图实现的目标没有任何意义。这是我最终选择的解决方案:
sealed trait ReadOnlyPlayer extends Player
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[ReadOnlyPlayer])
def hit(damage: Int) = { _health = max(0, _health - damage); this }
lazy val safeCopy: ReadOnlyPlayer = ReadOnlyCopy
private object ReadOnlyCopy extends ReadOnlyPlayer {
override def health = _health
// noop
override def hit (damage: Int) = this
override def play(players: List[ReadOnlyPlayer]) = ()
}
}
嵌套对象列表:
$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class X(id: Int) { object Y { def y = id } }
defined class X
scala> val xs = List.tabulate(10)(new X(_))
xs: List[X] = List(X@5f77d0f9, X@463fd068, X@895e367, X@1b266842, X@7a3793c7, X@42b3b079, X@651aed93, X@4dd6fd0a, X@bb9e6dc, X@5456afaa)
scala> val Ys = xs map (_.Y)
Ys: List[x.Y.type forSome { val x: X }] = List(X$Y$@43c67247, X$Y$@fac80, X$Y$@726386ed, X$Y$@649f2009, X$Y$@14bb2297, X$Y$@69adf72c, X$Y$@797501a, X$Y$@1a15b789, X$Y$@57f791c6, X$Y$@51650883)
scala> val ys = Ys map (_.y)
ys: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
为了锻炼我在 Scala 特定功能上的 OOP 能力,我尝试设计一个游戏,其中我有 Player
class。它有一个抽象方法 play
,它决定给定玩家列表(不同于调用该方法的玩家)采取什么行动。我想阻止 play
方法改变其他玩家的状态。正确的玩法是施放Spell
,让系统将其效果反映到其他玩家身上。
然而,play
方法需要其他玩家的读取权限来决定策略。因此,我创建了一个内部单例 ReadOnlyPlayer
。我将其设为单例以防止一遍又一遍地复制,并且每次都简单地 returning 这个单例。
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[/*?*/]) // how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[/*?*/]) = ()
}
}
由于我添加评论的行,我无法编译它。我知道有许多解决此问题的方法:
如果它是 class 而不是单例,我可以使用
Player#ReadOnlyPlayer
。我试过了,效果很好。但是,这需要每次都创建一个新副本,所以如果我想这样做,实际上创建一个单独的不可变 class 会更好。我可以手动实现单例模式,并且总是 return 此 class 的相同实例。
我可以将 class 设为私有并且只声明
Player
,但我希望我的客户知道他们明确知道他们将无法修改Player
实例。我可以使用具有有意义名称的密封空特征来做到这一点。
我知道如何以各种方式处理这个问题,所以我的问题更多是出于好奇:如何表示内部单例类型?
请注意,我在回答时并没有完全理解您要做什么来制作内部单例列表。
通常使用SingletonName.type
访问单例类型。所以,在你的情况下,它看起来像这样:
abstract class Player(private var _health: Int = 0) {
def health = _health
def play(players: List[ReadOnlyPlayer.type]) = ()// how to denote inner type ReadOnlyPlayer ?
def hit(damage: Int) = { _health = Math.max(0, _health - damage); this }
def safeCopy = ReadOnlyPlayer
final object ReadOnlyPlayer extends Player {
override def health = _health
// noop
override def hit (damage: Int ) = this
override def play(players: List[ReadOnlyPlayer.type]) = ()
}
}
正如@lloydme 指出的那样,我试图实现的目标没有任何意义。这是我最终选择的解决方案:
sealed trait ReadOnlyPlayer extends Player
abstract class Player(private var _health: Int = 0) {
Check.isPositive(_health)
def health = _health
def play(players: List[ReadOnlyPlayer])
def hit(damage: Int) = { _health = max(0, _health - damage); this }
lazy val safeCopy: ReadOnlyPlayer = ReadOnlyCopy
private object ReadOnlyCopy extends ReadOnlyPlayer {
override def health = _health
// noop
override def hit (damage: Int) = this
override def play(players: List[ReadOnlyPlayer]) = ()
}
}
嵌套对象列表:
$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class X(id: Int) { object Y { def y = id } }
defined class X
scala> val xs = List.tabulate(10)(new X(_))
xs: List[X] = List(X@5f77d0f9, X@463fd068, X@895e367, X@1b266842, X@7a3793c7, X@42b3b079, X@651aed93, X@4dd6fd0a, X@bb9e6dc, X@5456afaa)
scala> val Ys = xs map (_.Y)
Ys: List[x.Y.type forSome { val x: X }] = List(X$Y$@43c67247, X$Y$@fac80, X$Y$@726386ed, X$Y$@649f2009, X$Y$@14bb2297, X$Y$@69adf72c, X$Y$@797501a, X$Y$@1a15b789, X$Y$@57f791c6, X$Y$@51650883)
scala> val ys = Ys map (_.y)
ys: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)