25
votes

To define a singleton, should I use Kotlin object declaration or to make an ordinary Kotlin class and inject it using dagger? In my opinion the first option is definitely easier but there may be a reason to use dagger in this situation that I'm not aware of.

Option 1 (notice object keyword):

object SomeUtil {
    // object state (properties)

    fun someFunction(number: Long) {
        // ...
    }
}

Option 2 (notice class keyword):

class SomeUtil {
    // object state (properties)

    fun someFunction(number: Long) {
        // ...
    }
}
@Module
class AppModule {

    @Provides
    @Singleton
    internal fun provideTheUtil() = SomeUtil()
}
class MainActivity : BaseActivity() {

    @Inject internal lateinit var util: SomeUtil
}

UPDATE 2019-07-03

@Blackbelt said in comments that we should prefer option 2 for testability. But libraries like MockK can mock objects too. So do you still think option 2 is the preferred one?

2
this situation that I'm not aware of, testability ?Blackbelt
The only real reason you'd create this wrapper "util" class would be for testing, otherwise its pointless abstraction.Mark Keen
@MarkKeen I updated the question to generalize it.Mahozad

2 Answers

2
votes

You might want to reconsider the need of NumberFormatUtil being a singleton. It might be cheaper if you use @Reusable with Dagger or even a factory without any scope directly.

If NumberFormatUtil is fairly simple and only provides a few utility methods, no state and no need for mocking in tests, you could use an object implementation, maybe using @JvmStatic for Java-inter-operability. But then you could go for global utility (extension) functions as well:

package xyz

fun formatNumber(number: Long) {
    // ...
}

fun Long.format() = formatNumber(this)
0
votes

You should use option 2.

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance. This is useful when exactly one object is needed to coordinate actions across the system.

From: Singleton Pattern

So, a singleton is single instance in a scope. In case of Android, it is virtual machine instance running the app. In case you need custom scopes, you have to use option 2 only.

But, if you have only static methods inside the object you want to inject its better to keep them as global methods and even get rid of object. No need to inject anything. It is similar to a java class with only static methods (I mentioned this point as it is a usual way of creating Utility classes).

However, if the object also has some state. I would recommend going dagger way. The object way does not provide with dependency injection. It only creates a Singleton. Your purpose for using dagger is dependency injection.