2016-01-11 2 views
3

Я хотел бы инициализировать свойства моего класса. Поскольку я сильно использую функциональные элементы Kotlin, я бы хотел поставить эти инициализации на хорошо названные функции, чтобы повысить читаемость моего кода. Проблема в том, что я не могу назначить свойство val, если код не находится в блоке init, а в функции, которая вызывается из блока init.Невозможно вызвать функцию из блока init из-за свойства val

Можно ли разделить инициализацию класса на разные функции, если свойства являются vals?

Вот код:

val socket: DatagramSocket = DatagramSocket() 
    val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() 
    val broadcastAddresses: List<InetAddress> 

    init { 
     socket.broadcast = true 
     val interfaceAddresses = ArrayList<InterfaceAddress>() 
     collectValidNetworkInterfaces(interfaceAddresses) 
     collectBroadcastAddresses(interfaceAddresses) 
    } 

    private fun collectValidNetworkInterfaces(interfaceAddresses: ArrayList<InterfaceAddress>) { 
     NetworkInterface.getNetworkInterfaces().toList() 
       .filter { validInterface(it) } 
       .forEach { nInterface -> nInterface.interfaceAddresses.toCollection(interfaceAddresses) } 
    } 

    private fun collectBroadcastAddresses(interfaceAddresses: ArrayList<InterfaceAddress>) { 
     broadcastAddresses = interfaceAddresses 
       .filter { address -> address.broadcast != null } 
       .map { it.broadcast } 
    } 

Конечно, это не компиляции, потому что collectBroadcastAddresses функция пытается переназначить broadcastAddresses Валу. Хотя я не хочу помещать код этой функции в блок init, потому что не очевидно, что делает код, и имя функции говорит об этом очень красиво.

Что я могу сделать в таких случаях? Я хочу, чтобы мой код был чистым, это самый важный момент!

+0

Можем ли мы использовать lateinit как: lateinit VAL broadcastAddresses: Список ? – user1453345

ответ

7

Один из способов подхода к проблеме заключается в использовании pure functions для инициализации полей:

class Operation { 
    val socket = DatagramSocket().apply { broadcast = true } 
    val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() 
    val broadcastAddresses = collectBroadcastAddresses(collectValidNetworkInterfaces()) 

    private fun collectValidNetworkInterfaces() = 
     NetworkInterface.getNetworkInterfaces().toList() 
      .filter { validInterface(it) } 
      .flatMap { nInterface -> nInterface.interfaceAddresses } 

    private fun validInterface(it: NetworkInterface?) = true 

    private fun collectBroadcastAddresses(interfaceAddresses: List<InterfaceAddress>) { 
     interfaceAddresses 
      .filter { address -> address.broadcast != null } 
      .map { it.broadcast } 
    } 
} 

Обратите внимание, как инициализация socket поле использует apply расширение.

Я часто нахожу полезным для извлечения манипуляции коллекции подпрограмм в методы расширения:

class Operation { 
    val socket = DatagramSocket().apply { broadcast = true } 
    val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() 
    val broadcastAddresses = NetworkInterface.getNetworkInterfaces() 
     .collectValidNetworkInterfaces { validInterface(it) } 
     .collectBroadcastAddresses() 

    private fun validInterface(it: NetworkInterface?) = true 
} 

fun Iterable<InterfaceAddress>.collectBroadcastAddresses(): List<InetAddress> = 
    filter { address -> address.broadcast != null }.map { it.broadcast } 

fun Enumeration<NetworkInterface>.collectValidNetworkInterfaces(isValid: (NetworkInterface) -> Boolean = { true }) = 
    toList() 
     .filter { isValid(it) } 
     .flatMap { nInterface -> nInterface.interfaceAddresses } 
Смежные вопросы