За да упражня способностите си за ООП върху специфични за Scala функции, се опитах да проектирам игра, в която имам Player
клас. Той има абстрактен метод play
, който решава, като има списък с играчи (различен от играча, на който е извикан методът), какво действие да предприеме. Исках да попреча на метода play
да променя състоянието на тези други играчи. Правилният начин да играете е да хвърлите Spell
и да оставите системата да отрази ефекта му върху другите играчи.
И все пак методът play
се нуждае от достъп за четене до другите играчи, за да реши стратегия. Така създадох вътрешен сингълтон ReadOnlyPlayer
. Направих го сингълтън, за да предотвратя копирането отново и отново и просто да връщам този сингълтон всеки път.
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[/*?*/]) = ()
}
}
Не мога да го накарам да се компилира заради реда, на който съм поставил коментар. Знам за няколко заобиколни решения на този проблем:
ако беше клас вместо сингълтън, можех да използвам
Player#ReadOnlyPlayer
. Опитах, работи добре. Това обаче изисква да се създава ново копие всеки път, така че ако исках да направя това, всъщност би било по-добре да създам отделен неизменен клас.Бих могъл ръчно да внедря сингълтон модел и винаги да връщам едно и също копие на този клас.
Бих могъл да направя класа частен и да декларирам само
Player
, но искам клиентите ми да знаят, че изрично знаят, че няма да могат да променят екземпляраPlayer
. Мога да направя това, като използвам запечатана празна характеристика със смислено име.
Знам как мога да се справя с това по различни начини, така че въпросът ми е по-скоро от любопитство: как може да се обозначи вътрешен сингълтън тип?