如何在Kotlin中做到这一点?

dwbf0jvd  于 2023-06-24  发布在  Kotlin
关注(0)|答案(3)|浏览(167)

我正在尝试为一个国家创建一个简单的数据类。

data class Country(val name: String, val capital: String)

这个很好用。现在我想添加邻居。

data class Country(val name: String, val capital: String, val neighbors: List<Country>)

这引起了问题。加拿大和美国是邻居。我如何干净地示例化这些国家对象中的每一个?我不想让neighbors元素是可变的。有可能做到这一点吗?(我首先尝试创建没有邻居的国家,然后使用复制构造函数创建有邻居的国家。但是equals方法有问题。)这看起来是一个简单的问题,但我不知道如何解决。

xa9qqrwz

xa9qqrwz1#

我认为你应该用邻居的id来表示邻居,然后创建一个函数来执行查询。这是我的解决方案

data class Country(
    val id : Int,
    val name: String,
    val capital: String,
    val neighbors: List<Int> = emptyList(),
){
    // Function to retrieve neighbors
    fun  getNeighbors(countries : List<Country>) : List<Country>{
        return  countries.filter { it.id in neighbors }
    }
}

val Togo = Country(id = 1, name = "TOGO", capital = "Lome", neighbors = listOf(2, 3, 4))
val Benin = Country(id = 2, name = "Benin", capital = "Porto Novo", neighbors = listOf(1))
val Ghana = Country(id = 3, name = "Ghana", capital = "Accra", neighbors = listOf(1, 2))
val Burkina = Country(id = 4, name = "Burkina Faso", capital = "Ouagadougou", neighbors = listOf(1, 2, 3))

val allCountries = listOf(Togo, Benin, Ghana, Burkina)

//Here you have the list of neighbors
val beninNeighbors = Benin.getNeighbors(allCountries)
6ovsh4lw

6ovsh4lw2#

不知道你的案子到底是什么。
但首先,我认为这种数据表示是有问题的。例如,想象一下toString方法。美国将调用邻居的toString,它将调用加拿大的toString,然后返回美国,这永远不会结束...
另一种方法是将邻居的逻辑保存在单独的类中。它可以被封装,并且不可能配置不正确的状态,其中美国是加拿大的邻居,但反之亦然。
它可以看起来像这样:

data class Country(val name: String, val capital: String)

class Neighbours(vararg neighbour: Pair<Country, Country>) {
    private val neighbours: MutableMap<Country, MutableSet<Country>> = mutableMapOf()

    init {
        neighbour.forEach {
            neighbours.getOrPut(it.first) { mutableSetOf() }.add(it.second)
            neighbours.getOrPut(it.second) { mutableSetOf() }.add(it.first)
        }
    }

    fun getNeighbours(c: Country): Set<Country> = neighbours[c] ?: emptySet()
}

和用法示例

class Model() {
    val canada = Country("Canada", "Ottawa")
    val usa = Country("USA", "Washington")
    val mexico = Country("Mexico", "Mexico City")

    val neighbours = Neighbours(Pair(canada, usa), Pair(usa, mexico))

    fun usage() {
        println(usa.getNeighbours())
    }

    fun Country.getNeighbours() = neighbours.getNeighbours(this)
}

fun main() = Model().usage()
uemypmqf

uemypmqf3#

Edouardsepopo Zinnoussou的回答要求调用者传递allCountries集合。如果你不喜欢这样,那么这里有一个解决方案可以避免这种情况:

data class Country(val name: String, val capital: String) {
    val neighbors: Set<Country> by lazy {
        CountryFactory.neighborsByCountry[this]!!
    }
}

...使用lazy来处理数据的后期绑定。请注意,Country对象现在不会在toString/equality/etc中暴露邻居,但这里的策略是使用Factory来创建国家:

object CountryFactory {
    val togo = Country(name = "TOGO", capital = "Lome")
    val benin = Country(name = "Benin", capital = "Porto Novo")
    val ghana = Country(name = "Ghana", capital = "Accra")
    val burkina = Country(name = "Burkina Faso", capital = "Ouagadougou")
    val neighborsByCountry: Map<Country, Set<Country>> = mapOf(
        togo to setOf(benin, ghana, burkina),
        benin to setOf(togo),
        ghana to setOf(togo, benin),
        burkina to setOf(togo, benin, ghana),
    )
}

@Test
fun togoHasCorrectNeighbors() {
    CountryFactory.togo.neighbors.shouldContainAll(
        CountryFactory.benin, CountryFactory.ghana, CountryFactory.burkina,
    )
}

相关问题