Освоюємо Kotlin/Enum класи
Enum класи в Kotlin - це спеціальні класи для створення переліків (від англ. enumaration).
Простий перелік
[ред.]Перелік видів старовинної зброї може виглядати так:
enum class Weapon {
SWORD,
AXE,
BOW
}
Кожен елемент переліку є константою і об'єктом, розмежовуються елементи при переліченні комами.
Ініціалізація констант
[ред.]Перелік може мати конструктор і ініціалізувати певні властивості для кожного елементу переліку. Наприклад додамо значення шкоди для кожного виду зброї:
enum class Weapon (var damage:Int){
SWORD (15),
AXE (20),
BOW (16)
}
fun main(){
val weapon: Weapon = Weapon.AXE
println(weapon.damage) // 20
println(Weapon.BOW.damage) // 16
}
При потребі можна додавати кілька властивостей.
Визначення функцій у Enum класах
[ред.]Enum класи можуть містити також функції. Такі функції визначаються після переліку і крапки з комою:
enum class Weapon (var damage:Int){
SWORD (15),
AXE (20),
BOW (16);
fun getDescription():String{
return "Зброя:$this шкода:$damage"
}
}
fun main(){
val weapon=Weapon.AXE
println(weapon.getDescription())
}
Результат:
Зброя:AXE шкода:20 |
Властивості та функції Enum класів
[ред.]Всі переліки володіють двома властивостями name та ordinary. Перша властивість повертає ім'я переліку, друга порядковий номер переліку починаючи з нуля.
enum class Weapon (var damage:Int){
SWORD (15),
AXE (20),
BOW (16)
}
fun main(){
val weapon1=Weapon.AXE
println(weapon1.name) // AXE
println(weapon1.ordinal) // 1
}
Також, в Kotlin для Enum класу є додаткові функції:
- valueOf(value: String) - повертає об'єкт переліку по назві константи
- values() - повертає масив констант переліку
Замість функції values() можна скористатись властивістю EnumClass.entries: EnumEntries<EnumClass> // спеціалізований List<EnumClass>
enum class Weapon (var damage:Int){
SWORD (15),
AXE (20),
BOW (16)
}
fun main() {
for(weapon in Weapon.values())
println("values(): "+weapon)
for (weapon in Weapon.entries)
println("Entries: "+weapon.toString())
val weapon2:Weapon=Weapon.valueOf("BOW")
println("valueOf(): "+weapon2)
}
Результат:
values(): SWORD values(): AXE values(): BOW Entries: SWORD Entries: AXE Entries: BOW valueOf(): BOW |
Функція valueOf() викидає виняток IllegalArgumentException, якщо вказана назва не співпадає з константами переліку.
Анонімні класи
[ред.]Enum константи можуть декларувати свої власні анонімні класи із відповідними функціями та властивостями або заміщати (override) методи і властивості Enum класу:
enum class Weapon (){
SWORD{
override val damage = 20
override fun getUkrName(): String {
return "меч"
}
},
AXE{
override val damage = 25
override fun getUkrName(): String {
return "сокира"
}
},
BOW{
override val damage = 11
override fun getUkrName(): String {
return "лук"
}
};
abstract fun getUkrName():String
abstract val damage:Int
}
fun main() {
val weapon1 = Weapon.AXE
val weapon2 = Weapon.BOW
println("Зброя: ${weapon1.getUkrName()}, шкода: ${weapon1.damage}")
println("Зброя: ${weapon2.getUkrName()}, шкода: ${weapon2.damage}")
}
Результат:
Зброя: сокира, шкода: 25 Зброя: лук, шкода: 11 |
Реалізація інтерфейсів
[ред.]Enum класи також можуть реалізовувати інтерфейси:
interface Printable {
fun printInfo()
}
enum class Weapon : Printable {
SWORD {
override fun printInfo() {
println("меч")
}
},
AXE {
override fun printInfo() {
println("сокира")
}
},
BOW {
override fun printInfo() {
println("сокира")
}
}
}
fun main() {
Weapon.AXE.printInfo()
}
Приклади програм із застосуванням переліку
[ред.]Наступна програма створює двох солдат, які б'ються між собою (почергову наносять собі удари) поки в одного з них не закінчиться здоров'я. При цьому кожен солдат отримує при створенні зброю із списку переліку Weapon.
//перелік зброї
enum class Weapon (val damage:Int, val ukrName:String){
SWORD(16, "меч"),
AXE(20, "сокира"),
BOW(14, "лук")
}
//клас солдата
class Soldier(var name:String, var health:Int, val weapon:Weapon)
//функція, яка реалізовує удар одного солдата іншим,
//віднімається здоров'я у того солдата, якого вдарили
fun hit(soldier: Soldier, hittedSoldier: Soldier){
println (soldier.name+" вдарив "+hittedSoldier.name)
hittedSoldier.health=hittedSoldier.health-soldier.weapon.damage
if (hittedSoldier.health<=0) println(hittedSoldier.name+" помер")
}
fun main() {
val soldier1=Soldier("Adam", 100, Weapon.AXE)
val soldier2=Soldier("Ren", 100, Weapon.SWORD)
//солдати б'ються почергово до смерті одного з них
while ((soldier1.health>0)&&(soldier2.health>0)){
hit (soldier1, soldier2)
if (soldier2.health>0)hit (soldier2, soldier1)
}
}
Результат:
Adam вдарив Ren Ren вдарив Adam Adam вдарив Ren Ren вдарив Adam Adam вдарив Ren Ren вдарив Adam Adam вдарив Ren Ren вдарив Adam Adam вдарив Ren Ren помер |
Часто необхідно зробити певну дію в програмі, в залежності від певної константи переліку. Тоді можна перебрати константи з допомогою конструкції when. Наступний приклад демонструє присвоєння класу солдату (піхотинець або лучник) в залежності від його зброї:
enum class Weapon (val damage:Int, val ukrName:String){
SWORD(16, "меч"),
AXE(20, "сокира"),
BOW(14, "лук")
}
class Soldier(var name:String, var health:Int, val weapon:Weapon){
fun getClass():String{
return when(weapon){
Weapon.SWORD->"піхотинець"
Weapon.AXE->"піхотинець"
Weapon.BOW->"лучник"
}
}
}
fun main() {
val soldier1=Soldier("Adam", 100, Weapon.AXE)
val soldier2=Soldier("Ren", 100, Weapon.SWORD)
println("${soldier1.name} - ${soldier1.getClass()}")
println("${soldier2.name} - ${soldier2.getClass()}")
}
Результат:
Adam - піхотинець Ren - піхотинець |
В конструкції when необхідно перерахувати усі можливі випадки переліку або застосувати else.