Как справиться с полиморфизмом в котлине - PullRequest
0 голосов
/ 28 декабря 2018

Я работаю с абстрактным классом и двумя конкретными, которые реализуют абстрактный.Диаграмма выглядит следующим образом: enter image description here

Мои занятия выглядят так:

abstract class NavItem() {
    var attributes: String = ""
    var text = ""
}

class NavMenu(val items: MutableList<NavItem>) : NavItem()

class NavLink(var shortText: String) : NavItem()

Проблема в том, что я пытаюсь работать с элементами, которые могут бытьNavMenu или NavLinks, NavMenus имеет коллекцию NavLinks.

Я пытаюсь работать с элементами, используя полиморфизм в качестве следующего кода:

navMenu.items.forEach{ item ->
            buildNavItem(item)
        }

методы buildNavItem выглядят так:

private fun buildNavItem(navMenu: NavMenu){
        navMenu.items
        navMenu.attributes
        navMenu.items
    }

    private fun buildNavItem(navItem: NavItem){
        navItem.text
        navItem.attributes
    }

    private fun buildNavItem(navLink: NavLink){
        navLink.text
        navLink.attributes
    }

Но код всегда попадает в buildNavItem (navItem: NavItem), даже когда для каждого я иногда вижу, что это элемент NavLink или NavMenu.

Есть какие-нибудь предложения?

Спасибо !!

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Проблема:

navMenu.items.forEach { item ->
    item.buildNavItem()
}

Поскольку items имеет тип List<NavMenu>, компилятор вызовет функцию, которая подходит для item типа NavMenuв этом случае перегрузка, которая принимает NavMenu.

Решение:

Чтобы вызвать более конкретную перегрузку, компилятору необходимо знать тип.Вы можете интеллектуально разыграть предметы, и будет вызвана соответствующая функция:

private fun buildNavItem(navMenu: NavMenu) {
   when(navMenu){
      is NavItem -> buildNavItem(navMenu) // navMenu is smart casted to NavItem
      is NavLink -> buildNavItem(navMenu) // navMenu is smart casted to NavLink
      else -> throw IllegalStateException("Unknown subtype ${navMenu::class.simpleName} of NavMenu")
   }
}

Таким образом, когда вы вызываете buildNavItem, вы делегируете соответствующую функцию.

0 голосов
/ 28 декабря 2018

Это не так, как работает полиморфизм.У вас есть список navMenu.items, который является типом MutableList<NavItem>, он может хранить NavItem s или его потомков.В функции forEach вы просматриваете каждый элемент, который имеет тип NavItem, и вызываете функцию buildNavItem(item).В этом случае buildNavItem(navItem: NavItem) всегда вызывается.Чтобы вызвать тот же метод с другим параметром, вам нужно явно привести его к этому типу.То, что я рекомендую, и именно так работает полиморфизм, - это создать функцию buildNavItem() в классе NavItem и реализовать ее в потомках:

abstract class NavItem() {
    var attributes: String = ""
    var text = ""
    abstract fun buildNavItem()
}

class NavMenu(val items: MutableList<NavItem>) : NavItem() {
    override fun buildNavItem() {
        // ... your concrete implementation for NavMenu
    }
}

class NavLink(var shortText: String) : NavItem() {
    override fun buildNavItem() {
        // ... your concrete implementation for NavLink
    }
}

И затем вы можете вызвать ее в функции forEach:

navMenu.items.forEach { item ->
        item.buildNavItem()
}

В этом случае для правильного объекта будет вызываться функция buildNavItem(), которая хранится в navMenu.items, т.е. если это объект типа NavLink, то функция 'buildNavItem ()',переопределено в NavLink классе, будет вызвано.

...