weliem / blessed-android

BLESSED, a Bluetooth Low Energy (BLE) library for Android
MIT License
557 stars 120 forks source link

Convert callbacks to interface #12

Closed fonix232 closed 5 years ago

fonix232 commented 5 years ago

Is there any specific reason why the Central and Peripheral callbacks are abstract classes, instead of interfaces? Having interfaces (with a default abstract implementation) would be much nicer than having to rely on abstract classes.

weliem commented 5 years ago

There are many discussions online about the topic of 'abstract classes or interfaces'.

The reasons I choose for abstract classes are:

fonix232 commented 5 years ago

The reason why interfaces would be better is because some use-cases might require composition of these things. Let's say you want a class that handles both Peripheral and Connection callbacks - you can't do it with abstract classes.

With interfaces, you could have the following (please forgive the use of Kotlin, I find it easier than writing Java lately):

interface ICallback {
    fun call1()
    fun call2()
    fun call3()
}

abstract class Callback: ICallback {
    override fun call1() {}
    override fun call2() {}
    override fun call3() {}
}

If you provide both, you don't force the users of your library to a fixed implementation (SOLID principles are important, yo!), but do provide a base implementation that can be used as you describe.

In my use-case, for example, I'd concentrate the management of a single actual device, into a single actual object, that would handle both the scan for itself. To achieve this, I'd much prefer using the object itself as the callbacks, instead of a local instance. With the current implementation, this is impossible.

Also, small sidenote - if you have both the interface and abstract classes, you still provide all the points you listed, while keeping the implementation of the callbacks separate from their actual implementation, while maintaining the flexibility of the implementations. SOLID demands that you limit the direct references to implementations to a minimum, and instead use abstraction. While they do sound the same, an abstract class is technically not abstraction as it already contains the implementation. Interfaces are simply much more widely usable than an abstract class.

And if you decided to port the library over to Kotlin, it has interface delegation as well:

class MySuperDuperBluetoothClass: WhateverBase, ICentralCallback by MySuperCentralCallback {

}
weliem commented 5 years ago

Not sure if agree with what you are saying. In my example app I also handle everything in 1 class and the callbacks are simply member variables. Have a look here: https://github.com/weliem/blessed-android/blob/master/app/src/main/java/com/welie/blessedexample/BluetoothHandler.java

That seems to be exactly what you are trying to do. The only difference is that you had in mind to make the class 'implement' the interfaces....