官术网_书友最值得收藏!

Singleton

This is the most popular single guy in the neighborhood. Everybody knows him, everybody talks about him, and anybody can find him easily.

Even people who will frown when other design patterns are mentioned will know it by name. At some point, it was even proclaimed an anti-pattern, but only because of its wide popularity. So, for those who are hearing about it for the first time, what is this pattern about? 

Usually, if you have an object, you can create as many of its instances as you want. Say, for example, you have the Cat class:

class Cat

You can produce as many of its instances (cats, to be precise), as you want:

val firstCat = Cat()
val secondCat = Cat()
val yetAnotherCat = Cat()

And there's no problem with that. 

What if we wanted to disallow such behavior? Clearly, we have to create an object in some way for the first time. But from the second time on, we need to recognize that this object was initialized once already, and returns its instance instead. That's the main idea behind being a Singleton.

In Java and some other languages, this task is quite complex. It's not enough to simply make the constructor private and remember that the object was initialized at least once already. We also need to prevent race conditions, where two separate threads try to initialize it exactly at the same time. If we allowed that, it would break the entire concept of a Singleton, as two threads would hold references to two instances of the same object.

Solving this problem in Java requires doing one of the following:

  • Accepting that a Singleton will initialize eagerly when your application starts, and not when it is first accessed
  • Writing some smart code to prevent such race conditions and still stay performant
  • Using a framework that already solves it

Kotlin just introduces a reserved keyword for that. Behold, an object as follows:

object MySingelton{}

You don't need curly brackets there. They're just for visual consistency.

This combines declaration and initialization in one keyword. From now on, MySingleton can be accessed from anywhere in your code, and there'll be exactly one instance of it.

Of course, this object doesn't do anything interesting. Let's make it count the number of invocations instead:

object CounterSingleton {
private val counter = AtomicInteger(0)

fun increment() = counter.incrementAndGet()
}

We won't test it for thread safety yet this is a topic that will be covered in Chapter 8, Threads and Coroutines, which deals with threads. For now, we test it only to see how we call our Singleton:

for (i in 1..10) {
println(CounterSingleton.increment())
}

This will print numbers between 1 and 10, as expected. As you can see, we don't need the getInstance() method at all.

The object keyword is used for more than just creating Singletons. We'll discuss it in depth later.

Objects can't have constructors. If you want some kind of initialization logic for your Singleton, such as loading data from the database or over the network for the first time, you can use the init block instead:

object CounterSingleton {

init {
println("I was accessed for the first time")
}
// More code goes here
}

It is also demonstrated that Singletons in Kotlin are initialized lazily, and not eagerly, as some could suspect from the ease of their declaration. Just like regular classes, objects can extend other classes and implement interfaces. We'll come back to this in Chapter 10, Idioms and Anti-Patterns.

主站蜘蛛池模板: 海淀区| 台江县| 桂阳县| 广丰县| 霍州市| 东城区| 醴陵市| 临汾市| 开封市| 望谟县| 阜阳市| 铅山县| 浦江县| 彭州市| 清徐县| 太仓市| 东平县| 昆山市| 河西区| 库伦旗| 涡阳县| 吴川市| 内江市| 珲春市| 广宗县| 呼和浩特市| 宜昌市| 太和县| 岳普湖县| 镇赉县| 阿克苏市| 蕲春县| 庄河市| 南华县| 浦北县| 土默特右旗| 姚安县| 泽州县| 临澧县| 建平县| 衡阳县|