HiveBrain v1.2.0
Get Started
← Back to all entries
patternkotlinMinor

Observer pattern using a set of observers and delegated properties

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
observerspropertiesobserverdelegatedpatternusingandset

Problem

The idea is to implement the observer pattern, with a separate notification method for each observed property of the observed object. Let me start with a simplified use case:

class Point {
    val observers: ObserverSet()
    val x by observers.observe(0f, PointObserver::xChanged)
    val y by observers.observe(0f, PointObserver::yChanged)
}

interface PointObserver {
    fun xChanged(old: Float, new: Float)
    fun yChanged(old: Float, new: Float)
}

class PointView(point: Point) {
    init {
        point.observers.add(object : PointObserver {
            override fun xChanged(old: Float, new: Float) { ... }
            override fun yChanged(old: Float, new: Float) { ... }
        })
    }
}


I'm new to Kotlin, so I'd like some feedback on the following implementation:

```
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
* A set of observers for a particular object, to easily implement the Observer Pattern without needing inheritance.
*
* This can be made a public property of the object. Call [observe] to create delegated properties for each property
* that observers need to be notified about.
*
* @param O The type of the observers, typically an interface.
*/
class ObserverSet {

private val observers = mutableSetOf()
private val properties = mutableListOf>()

/**
* Sets whether an observer is present in the set. If the observer was actually added to the set, its notification
* methods will be called with the current value of the property.
*
* @param observer The observer.
* @param present If true, the observer will be added to the set if not already there. If false, the observer will
* be removed from the set if it's there.
*/
fun toggle(observer: O, present: Boolean) {
if (present) {
val wasPresent = observer in observers
observers.add(observer)
if (!wasPresent) {
init(observer)
}
} e

Solution

-
You don't need a wasPresent variable. MutableSet.add returns true if the element was added to the set:

if (observers.add(observer)) {
    init(observer)
}


-
Sometimes in Kotlin you don't have to declare temporary variables so that you can do something with a return value before returning it. e.g.:

return ObservedProperty(initialValue, onChanged).apply { properties.add(this) }


Unfortunately this can sometimes look a bit strange using this, etc. but in Kotlin 1.1 you can use bound callable references:

return ObservedProperty(initialValue, onChanged).apply(properties::add)


-
You might want to take a look at Delegates.observable - stdlib - Kotlin Programming Language which you may be able to reuse to improve and reduce your code.

Code Snippets

if (observers.add(observer)) {
    init(observer)
}
return ObservedProperty(initialValue, onChanged).apply { properties.add(this) }
return ObservedProperty(initialValue, onChanged).apply(properties::add)

Context

StackExchange Code Review Q#155580, answer score: 6

Revisions (0)

No revisions yet.