6

Assume I have a data class:

data class SensorData(val name: String, val temp : Double)

I create this SensorData object from either an REST service or by internal setter method, whereas name is always populated and temp might be empty.

Further on, I need this SensorData object through several classes, thats I thought of using a singleton.

Obviously I need object keyword as described here, but how can I combine data class object ?

Sergio
  • 27,326
  • 8
  • 128
  • 149
Noam Silverstein
  • 819
  • 2
  • 12
  • 18
  • Using a singleton is just wrong for this purpose. Just pass the instance to the classes that need it. – marstran May 23 '19 at 09:43

4 Answers4

4

I think you got the concept of a Singleton wrong:

"The singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance"

It is not only meant to be used to make it public to all classes, but to limit the number of instances.

A data class is a class to store data, why should it be a Singleton?

Rethink your architecture to make it accessible where you need it.

janavarro
  • 869
  • 5
  • 24
4

You can use companion object to keep a reference to your data object:

data class SensorData(val name: String, var temp : Double) {
    companion object {
        @Volatile
        @JvmStatic
        private var INSTANCE: SensorData? = null

        @JvmStatic
        @JvmOverloads
        fun getInstance(name: String = "default", temp : Double = 0.0): SensorData = INSTANCE ?: synchronized(this) {
            INSTANCE ?: SensorData(name, temp).also { INSTANCE = it }
        }
    }
}

And use it like this:

val name1 = SensorData.getInstance("name", 5.0).name

// Or with default values:
val name2 = SensorData.getInstance().name
Sergio
  • 27,326
  • 8
  • 128
  • 149
  • What happens when the temperature changes without knowing sensors name? – Noam Silverstein May 24 '19 at 12:42
  • If you want to change the temperature use `SensorData.getInstance().temp = 36.6`. But in this case name will be set as `"default"` or whatever you provide as default value if `INSTANCE` has not been initialized yet. – Sergio May 24 '19 at 13:21
0

Don't use a data class as a singleton. That's not what they are designed for. A better approach would be to create a wrapper object around your data class, which handles your SensorData-Object(s). This will also allow you to use multiple SensorData objects (maybe needed in future) or replace the current one with a new one if you poll the REST-Service a second time.

object SensorDataService {
 var sensorData: SensorData? = null
}

data class SensorData(val name: String, val temp : Double)
asuras
  • 123
  • 7
  • 2
    You should never put mutable data in a singleton object. Global shared mutable data is a big no-no. – marstran May 23 '19 at 09:41
  • @marstran It surely is, but it's also an answer to the original question. The setter to the sensorData can be private as long as some initialization logic is provided. – asuras May 23 '19 at 14:09
  • @marstran Is there an example somewhere why not? – Noam Silverstein May 24 '19 at 09:19
  • 1
    @NoamSilverstein Here's an SO question about it: https://stackoverflow.com/questions/44219903/why-is-shared-mutability-bad – marstran May 24 '19 at 09:48
  • Shared mutable data exposes your data to concurrent write access. The data can be changed by multiple threads at the same time. Imagine you share an int variable (i = 3). One thread adds +1 and the other multiplies by 2. Depending on which thread is faster you either have (3 + 1) * 2 = 8 or 3 * 2 + 1 = 7. Which result is the correct one: 7 or 8? How do you handle the case of an incorrect calculation? – asuras May 24 '19 at 10:24
-1

In my opinion, you should rethink your architecture as data class is used to store data so why it should be a singleton? It is not only meant to be used to make it public to all classes but to limit the number of instances.

Rahul
  • 3,293
  • 2
  • 31
  • 43